aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/ext/census/gen/census.pb.h2
-rw-r--r--src/core/ext/census/gen/trace_context.pb.c45
-rw-r--r--src/core/ext/census/gen/trace_context.pb.h46
-rw-r--r--src/core/ext/census/grpc_filter.c4
-rw-r--r--src/core/ext/census/trace_context.c2
-rw-r--r--src/core/ext/census/trace_context.h3
-rw-r--r--src/core/ext/client_channel/client_channel.c35
-rw-r--r--src/core/ext/client_channel/client_channel.h4
-rw-r--r--src/core/ext/client_channel/connector.c6
-rw-r--r--src/core/ext/client_channel/connector.h7
-rw-r--r--src/core/ext/client_channel/http_connect_handshaker.c10
-rw-r--r--src/core/ext/client_channel/subchannel.c13
-rw-r--r--src/core/ext/client_channel/subchannel.h2
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c66
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c84
-rw-r--r--src/core/ext/resolver/dns/native/dns_resolver.c5
-rw-r--r--src/core/ext/resolver/sockaddr/sockaddr_resolver.c2
-rw-r--r--src/core/ext/transport/chttp2/client/chttp2_connector.c14
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.c16
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c2
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c2
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.c14
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_encoder.c3
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_encoder.h3
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_plugin.c3
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c764
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c22
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.c13
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.c23
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.c11
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.c152
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c196
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.h20
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c41
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h12
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.c34
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h125
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c99
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_lists.c43
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c126
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_api_dummy.c2
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c55
-rw-r--r--src/core/lib/channel/channel_stack.c43
-rw-r--r--src/core/lib/channel/channel_stack.h19
-rw-r--r--src/core/lib/channel/compress_filter.c94
-rw-r--r--src/core/lib/channel/connected_channel.c6
-rw-r--r--src/core/lib/channel/connected_channel.h5
-rw-r--r--src/core/lib/channel/deadline_filter.c15
-rw-r--r--src/core/lib/channel/handshaker.c14
-rw-r--r--src/core/lib/channel/handshaker.h8
-rw-r--r--src/core/lib/channel/http_client_filter.c246
-rw-r--r--src/core/lib/channel/http_server_filter.c296
-rw-r--r--src/core/lib/channel/message_size_filter.c22
-rw-r--r--src/core/lib/compression/algorithm_metadata.h8
-rw-r--r--src/core/lib/compression/compression.c40
-rw-r--r--src/core/lib/http/httpcli_security_connector.c2
-rw-r--r--src/core/lib/iomgr/closure.c9
-rw-r--r--src/core/lib/iomgr/closure.h6
-rw-r--r--src/core/lib/iomgr/combiner.c12
-rw-r--r--src/core/lib/iomgr/endpoint.c5
-rw-r--r--src/core/lib/iomgr/endpoint.h5
-rw-r--r--src/core/lib/iomgr/error.c154
-rw-r--r--src/core/lib/iomgr/error.h13
-rw-r--r--src/core/lib/iomgr/error_internal.h54
-rw-r--r--src/core/lib/iomgr/ev_epoll_linux.c19
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c17
-rw-r--r--src/core/lib/iomgr/ev_posix.c6
-rw-r--r--src/core/lib/iomgr/ev_posix.h4
-rw-r--r--src/core/lib/iomgr/exec_ctx.c17
-rw-r--r--src/core/lib/iomgr/exec_ctx.h25
-rw-r--r--src/core/lib/iomgr/executor.c4
-rw-r--r--src/core/lib/iomgr/load_file.c2
-rw-r--r--src/core/lib/iomgr/network_status_tracker.c3
-rw-r--r--src/core/lib/iomgr/resource_quota.c40
-rw-r--r--src/core/lib/iomgr/resource_quota.h6
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.c5
-rw-r--r--src/core/lib/iomgr/tcp_client_windows.c27
-rw-r--r--src/core/lib/iomgr/tcp_posix.c9
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.c6
-rw-r--r--src/core/lib/iomgr/tcp_server_windows.c2
-rw-r--r--src/core/lib/iomgr/tcp_uv.c7
-rw-r--r--src/core/lib/iomgr/tcp_windows.c27
-rw-r--r--src/core/lib/iomgr/udp_server.c41
-rw-r--r--src/core/lib/iomgr/udp_server.h5
-rw-r--r--src/core/lib/iomgr/unix_sockets_posix.c12
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.c2
-rw-r--r--src/core/lib/security/credentials/plugin/plugin_credentials.c22
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c115
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c6
-rw-r--r--src/core/lib/security/transport/security_connector.c2
-rw-r--r--src/core/lib/security/transport/security_handshaker.c15
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c69
-rw-r--r--src/core/lib/security/util/b64.c2
-rw-r--r--src/core/lib/slice/slice.c130
-rw-r--r--src/core/lib/slice/slice_hash_table.c (renamed from src/core/lib/transport/mdstr_hash_table.c)69
-rw-r--r--src/core/lib/slice/slice_hash_table.h (renamed from src/core/lib/transport/mdstr_hash_table.h)42
-rw-r--r--src/core/lib/slice/slice_intern.c344
-rw-r--r--src/core/lib/slice/slice_internal.h15
-rw-r--r--src/core/lib/slice/slice_string_helpers.c5
-rw-r--r--src/core/lib/slice/slice_string_helpers.h5
-rw-r--r--src/core/lib/slice/slice_traits.h44
-rw-r--r--src/core/lib/support/log_posix.c12
-rw-r--r--src/core/lib/support/time_windows.c8
-rw-r--r--src/core/lib/surface/call.c1045
-rw-r--r--src/core/lib/surface/call.h4
-rw-r--r--src/core/lib/surface/call_details.c10
-rw-r--r--src/core/lib/surface/call_log_batch.c23
-rw-r--r--src/core/lib/surface/channel.c106
-rw-r--r--src/core/lib/surface/channel.h11
-rw-r--r--src/core/lib/surface/completion_queue.c15
-rw-r--r--src/core/lib/surface/init.c6
-rw-r--r--src/core/lib/surface/lame_client.c16
-rw-r--r--src/core/lib/surface/server.c142
-rw-r--r--src/core/lib/surface/validate_metadata.c61
-rw-r--r--src/core/lib/surface/validate_metadata.h43
-rw-r--r--src/core/lib/surface/version.c4
-rw-r--r--src/core/lib/transport/bdp_estimator.c104
-rw-r--r--src/core/lib/transport/bdp_estimator.h76
-rw-r--r--src/core/lib/transport/connectivity_state.c1
-rw-r--r--src/core/lib/transport/error_utils.c124
-rw-r--r--src/core/lib/transport/error_utils.h56
-rw-r--r--src/core/lib/transport/http2_errors.h (renamed from src/core/ext/transport/chttp2/transport/http2_errors.h)36
-rw-r--r--src/core/lib/transport/metadata.c760
-rw-r--r--src/core/lib/transport/metadata.h137
-rw-r--r--src/core/lib/transport/metadata_batch.c246
-rw-r--r--src/core/lib/transport/metadata_batch.h76
-rw-r--r--src/core/lib/transport/method_config.c347
-rw-r--r--src/core/lib/transport/method_config.h139
-rw-r--r--src/core/lib/transport/pid_controller.c36
-rw-r--r--src/core/lib/transport/pid_controller.h17
-rw-r--r--src/core/lib/transport/service_config.c39
-rw-r--r--src/core/lib/transport/service_config.h10
-rw-r--r--src/core/lib/transport/static_metadata.c870
-rw-r--r--src/core/lib/transport/static_metadata.h672
-rw-r--r--src/core/lib/transport/status_conversion.c (renamed from src/core/ext/transport/chttp2/transport/status_conversion.c)38
-rw-r--r--src/core/lib/transport/status_conversion.h (renamed from src/core/ext/transport/chttp2/transport/status_conversion.h)19
-rw-r--r--src/core/lib/transport/timeout_encoding.c20
-rw-r--r--src/core/lib/transport/timeout_encoding.h4
-rw-r--r--src/core/lib/transport/transport.c99
-rw-r--r--src/core/lib/transport/transport.h34
-rw-r--r--src/core/lib/transport/transport_op_string.c26
144 files changed, 5795 insertions, 4091 deletions
diff --git a/src/core/ext/census/gen/census.pb.h b/src/core/ext/census/gen/census.pb.h
index dae583f33d..c8546eac2e 100644
--- a/src/core/ext/census/gen/census.pb.h
+++ b/src/core/ext/census/gen/census.pb.h
@@ -292,4 +292,4 @@ extern const pb_field_t google_census_Metric_fields[5];
} /* extern "C" */
#endif
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_GEN_CENSUS_PB_H */
diff --git a/src/core/ext/census/gen/trace_context.pb.c b/src/core/ext/census/gen/trace_context.pb.c
index c8aea324ce..f4126d4d80 100644
--- a/src/core/ext/census/gen/trace_context.pb.c
+++ b/src/core/ext/census/gen/trace_context.pb.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2016, Google Inc.
+ * Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,51 +31,24 @@
*
*/
/* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */
#include "src/core/ext/census/gen/trace_context.pb.h"
+/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
-const pb_field_t google_trace_TraceId_fields[3] = {
- PB_FIELD( 1, FIXED64 , OPTIONAL, STATIC , FIRST, google_trace_TraceId, hi, hi, 0),
- PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceId, lo, hi, 0),
+const pb_field_t google_trace_TraceContext_fields[5] = {
+ PB_FIELD( 1, FIXED64 , OPTIONAL, STATIC , FIRST, google_trace_TraceContext, trace_id_hi, trace_id_hi, 0),
+ PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, trace_id_lo, trace_id_hi, 0),
+ PB_FIELD( 3, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_id, trace_id_lo, 0),
+ PB_FIELD( 4, FIXED32 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_options, span_id, 0),
PB_LAST_FIELD
};
-const pb_field_t google_trace_TraceContext_fields[4] = {
- PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, google_trace_TraceContext, trace_id, trace_id, &google_trace_TraceId_fields),
- PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_id, trace_id, 0),
- PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, is_sampled, span_id, 0),
- PB_LAST_FIELD
-};
-
-
-/* Check that field information fits in pb_field_t */
-#if !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_32BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- *
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in 8 or 16 bit
- * field descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
-#endif
-
-#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_16BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- *
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in the default
- * 8 bit descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
-#endif
-
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/ext/census/gen/trace_context.pb.h b/src/core/ext/census/gen/trace_context.pb.h
index 263c4c58cb..ea127bf70a 100644
--- a/src/core/ext/census/gen/trace_context.pb.h
+++ b/src/core/ext/census/gen/trace_context.pb.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2016, Google Inc.
+ * Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,13 @@
*
*/
/* Automatically generated nanopb header */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */
#ifndef GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
#define GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
#include "third_party/nanopb/pb.h"
+
+/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
@@ -45,44 +47,35 @@ extern "C" {
#endif
/* Struct definitions */
-typedef struct _google_trace_TraceId {
- bool has_hi;
- uint64_t hi;
- bool has_lo;
- uint64_t lo;
-} google_trace_TraceId;
-
typedef struct _google_trace_TraceContext {
- bool has_trace_id;
- google_trace_TraceId trace_id;
+ bool has_trace_id_hi;
+ uint64_t trace_id_hi;
+ bool has_trace_id_lo;
+ uint64_t trace_id_lo;
bool has_span_id;
uint64_t span_id;
- bool has_is_sampled;
- bool is_sampled;
+ bool has_span_options;
+ uint32_t span_options;
+/* @@protoc_insertion_point(struct:google_trace_TraceContext) */
} google_trace_TraceContext;
/* Default values for struct fields */
/* Initializer values for message structs */
-#define google_trace_TraceId_init_default {false, 0, false, 0}
-#define google_trace_TraceContext_init_default {false, google_trace_TraceId_init_default, false, 0, false, 0}
-#define google_trace_TraceId_init_zero {false, 0, false, 0}
-#define google_trace_TraceContext_init_zero {false, google_trace_TraceId_init_zero, false, 0, false, 0}
+#define google_trace_TraceContext_init_default {false, 0, false, 0, false, 0, false, 0}
+#define google_trace_TraceContext_init_zero {false, 0, false, 0, false, 0, false, 0}
/* Field tags (for use in manual encoding/decoding) */
-#define google_trace_TraceId_hi_tag 1
-#define google_trace_TraceId_lo_tag 2
-#define google_trace_TraceContext_trace_id_tag 1
-#define google_trace_TraceContext_span_id_tag 2
-#define google_trace_TraceContext_is_sampled_tag 3
+#define google_trace_TraceContext_trace_id_hi_tag 1
+#define google_trace_TraceContext_trace_id_lo_tag 2
+#define google_trace_TraceContext_span_id_tag 3
+#define google_trace_TraceContext_span_options_tag 4
/* Struct field encoding specification for nanopb */
-extern const pb_field_t google_trace_TraceId_fields[3];
-extern const pb_field_t google_trace_TraceContext_fields[4];
+extern const pb_field_t google_trace_TraceContext_fields[5];
/* Maximum encoded size of messages (where known) */
-#define google_trace_TraceId_size 18
-#define google_trace_TraceContext_size 31
+#define google_trace_TraceContext_size 32
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
@@ -95,5 +88,6 @@ extern const pb_field_t google_trace_TraceContext_fields[4];
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* @@protoc_insertion_point(eof) */
#endif
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index 8e4d4732b8..65cfe1fa90 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -67,9 +67,7 @@ static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
channel_data *chand) {
grpc_linked_mdelem *m;
for (m = md->list.head; m != NULL; m = m->next) {
- if (m->md->key == GRPC_MDSTR_PATH) {
- gpr_log(GPR_DEBUG, "%s",
- (const char *)GRPC_SLICE_START_PTR(m->md->value->slice));
+ if (grpc_slice_eq(GRPC_MDKEY(m->md), GRPC_MDSTR_PATH)) {
/* Add method tag here */
}
}
diff --git a/src/core/ext/census/trace_context.c b/src/core/ext/census/trace_context.c
index fbb20d3448..47d0de19da 100644
--- a/src/core/ext/census/trace_context.c
+++ b/src/core/ext/census/trace_context.c
@@ -73,7 +73,7 @@ bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
}
// check fields
- if (!ctxt->has_trace_id) {
+ if (!ctxt->has_trace_id_hi || !ctxt->has_trace_id_lo) {
gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id");
return false;
}
diff --git a/src/core/ext/census/trace_context.h b/src/core/ext/census/trace_context.h
index 1cb5e26ea7..f391a1b7c1 100644
--- a/src/core/ext/census/trace_context.h
+++ b/src/core/ext/census/trace_context.h
@@ -38,6 +38,9 @@
#include "src/core/ext/census/gen/trace_context.pb.h"
+/* Span option flags. */
+#define SPAN_OPTIONS_IS_SAMPLED 0x01
+
/* Maximum number of bytes required to encode a TraceContext (31)
1 byte for trace_id field
1 byte for trace_id length
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 865e91a2b4..208c95b67a 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -54,6 +54,7 @@
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h"
@@ -89,7 +90,7 @@ static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *p) {
gpr_free(p);
}
-static const grpc_mdstr_hash_table_vtable method_parameters_vtable = {
+static const grpc_slice_hash_table_vtable method_parameters_vtable = {
method_parameters_free, method_parameters_copy};
static void *method_parameters_create_from_json(const grpc_json *json) {
@@ -171,7 +172,7 @@ typedef struct client_channel_channel_data {
/** service config in JSON form */
char *service_config_json;
/** maps method names to method_parameters structs */
- grpc_mdstr_hash_table *method_params_table;
+ grpc_slice_hash_table *method_params_table;
/** incoming resolver result - set by resolver.next() */
grpc_channel_args *resolver_result;
/** a list of closures that are all waiting for config to come in */
@@ -273,7 +274,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
char *lb_policy_name = NULL;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
- grpc_mdstr_hash_table *method_params_table = NULL;
+ grpc_slice_hash_table *method_params_table = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
@@ -379,7 +380,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->service_config_json = service_config_json;
}
if (chand->method_params_table != NULL) {
- grpc_mdstr_hash_table_unref(exec_ctx, chand->method_params_table);
+ grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
}
chand->method_params_table = method_params_table;
if (lb_policy != NULL) {
@@ -579,7 +580,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
gpr_free(chand->lb_policy_name);
gpr_free(chand->service_config_json);
if (chand->method_params_table != NULL) {
- grpc_mdstr_hash_table_unref(exec_ctx, chand->method_params_table);
+ grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
}
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
grpc_pollset_set_destroy(chand->interested_parties);
@@ -614,7 +615,7 @@ typedef struct client_channel_call_data {
// to avoid this without breaking the grpc_deadline_state abstraction.
grpc_deadline_state deadline_state;
- grpc_mdstr *path; // Request path.
+ grpc_slice path; // Request path.
gpr_timespec call_start_time;
gpr_timespec deadline;
wait_for_ready_value wait_for_ready_from_service_config;
@@ -643,6 +644,12 @@ typedef struct client_channel_call_data {
grpc_linked_mdelem lb_token_mdelem;
} call_data;
+grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
+ grpc_call_element *call_elem) {
+ grpc_subchannel_call *scc = GET_CALL((call_data *)call_elem->call_data);
+ return scc == CANCELLED_CALL ? NULL : scc;
+}
+
static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
GPR_TIMER_BEGIN("add_waiting_locked", 0);
if (calld->waiting_ops_count == calld->waiting_ops_capacity) {
@@ -1018,10 +1025,10 @@ static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg,
if (error == GRPC_ERROR_NONE) {
// Get the method config table from channel data.
gpr_mu_lock(&chand->mu);
- grpc_mdstr_hash_table *method_params_table = NULL;
+ grpc_slice_hash_table *method_params_table = NULL;
if (chand->method_params_table != NULL) {
method_params_table =
- grpc_mdstr_hash_table_ref(chand->method_params_table);
+ grpc_slice_hash_table_ref(chand->method_params_table);
}
gpr_mu_unlock(&chand->mu);
// If the method config table was present, use it.
@@ -1050,7 +1057,7 @@ static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&calld->mu);
}
}
- grpc_mdstr_hash_table_unref(exec_ctx, method_params_table);
+ grpc_slice_hash_table_unref(exec_ctx, method_params_table);
}
}
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config");
@@ -1064,7 +1071,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
call_data *calld = elem->call_data;
// Initialize data members.
grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
- calld->path = GRPC_MDSTR_REF(args->path);
+ calld->path = grpc_slice_ref_internal(args->path);
calld->call_start_time = args->start_time;
calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET;
@@ -1088,8 +1095,8 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
if (chand->lb_policy != NULL) {
// We already have a resolver result, so check for service config.
if (chand->method_params_table != NULL) {
- grpc_mdstr_hash_table *method_params_table =
- grpc_mdstr_hash_table_ref(chand->method_params_table);
+ grpc_slice_hash_table *method_params_table =
+ grpc_slice_hash_table_ref(chand->method_params_table);
gpr_mu_unlock(&chand->mu);
method_parameters *method_params = grpc_method_config_table_get(
exec_ctx, method_params_table, args->path);
@@ -1105,7 +1112,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
method_params->wait_for_ready;
}
}
- grpc_mdstr_hash_table_unref(exec_ctx, method_params_table);
+ grpc_slice_hash_table_unref(exec_ctx, method_params_table);
} else {
gpr_mu_unlock(&chand->mu);
}
@@ -1134,7 +1141,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
void *and_free_memory) {
call_data *calld = elem->call_data;
grpc_deadline_state_destroy(exec_ctx, elem);
- GRPC_MDSTR_UNREF(exec_ctx, calld->path);
+ grpc_slice_unref_internal(exec_ctx, calld->path);
GRPC_ERROR_UNREF(calld->cancel_error);
grpc_subchannel_call *call = GET_CALL(calld);
if (call != NULL && call != CANCELLED_CALL) {
diff --git a/src/core/ext/client_channel/client_channel.h b/src/core/ext/client_channel/client_channel.h
index f02587d0c1..5e6e64e58b 100644
--- a/src/core/ext/client_channel/client_channel.h
+++ b/src/core/ext/client_channel/client_channel.h
@@ -57,4 +57,8 @@ void grpc_client_channel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete);
+/* Debug helper: pull the subchannel call from a call stack element */
+grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
+ grpc_call_element *elem);
+
#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/ext/client_channel/connector.c b/src/core/ext/client_channel/connector.c
index 0582e5b372..7a720fd1bd 100644
--- a/src/core/ext/client_channel/connector.c
+++ b/src/core/ext/client_channel/connector.c
@@ -49,7 +49,7 @@ void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector,
connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify);
}
-void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_connector* connector) {
- connector->vtable->shutdown(exec_ctx, connector);
+void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, grpc_connector* connector,
+ grpc_error* why) {
+ connector->vtable->shutdown(exec_ctx, connector, why);
}
diff --git a/src/core/ext/client_channel/connector.h b/src/core/ext/client_channel/connector.h
index 395f89b3b2..9bff41f003 100644
--- a/src/core/ext/client_channel/connector.h
+++ b/src/core/ext/client_channel/connector.h
@@ -68,7 +68,8 @@ struct grpc_connector_vtable {
void (*ref)(grpc_connector *connector);
void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
/** Implementation of grpc_connector_shutdown */
- void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
+ void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
+ grpc_error *why);
/** Implementation of grpc_connector_connect */
void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
const grpc_connect_in_args *in_args,
@@ -83,7 +84,7 @@ void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
grpc_connect_out_args *out_args,
grpc_closure *notify);
/** Cancel any pending connection */
-void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_connector *connector);
+void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
+ grpc_error *why);
#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H */
diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/client_channel/http_connect_handshaker.c
index 622d236320..58ab233f1b 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.c
+++ b/src/core/ext/client_channel/http_connect_handshaker.c
@@ -123,7 +123,8 @@ static void handshake_failed_locked(grpc_exec_ctx* exec_ctx,
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
- grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint,
+ GRPC_ERROR_REF(error));
// Not shutting down, so the handshake failed. Clean up before
// invoking the callback.
cleanup_args_for_failure_locked(exec_ctx, handshaker);
@@ -251,15 +252,18 @@ static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx,
}
static void http_connect_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker_in) {
+ grpc_handshaker* handshaker_in,
+ grpc_error* why) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
gpr_mu_lock(&handshaker->mu);
if (!handshaker->shutdown) {
handshaker->shutdown = true;
- grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint,
+ GRPC_ERROR_REF(why));
cleanup_args_for_failure_locked(exec_ctx, handshaker);
}
gpr_mu_unlock(&handshaker->mu);
+ GRPC_ERROR_UNREF(why);
}
static void http_connect_handshaker_do_handshake(
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index 05b08826b6..f1e4e079e2 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -273,7 +273,8 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->disconnected);
c->disconnected = true;
- grpc_connector_shutdown(exec_ctx, c->connector);
+ grpc_connector_shutdown(exec_ctx, c->connector,
+ GRPC_ERROR_CREATE("Subchannel disconnected"));
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
@@ -637,9 +638,8 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_error *error = grpc_channel_stack_builder_finish(
exec_ctx, builder, 0, 1, connection_destroy, NULL, (void **)&con);
if (error != GRPC_ERROR_NONE) {
- const char *msg = grpc_error_string(error);
- gpr_log(GPR_ERROR, "error initializing subchannel stack: %s", msg);
- grpc_error_free_string(msg);
+ gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
+ grpc_error_string(error));
GRPC_ERROR_UNREF(error);
abort(); /* TODO(ctiller): what to do here? */
}
@@ -704,7 +704,6 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
const char *errmsg = grpc_error_string(error);
gpr_log(GPR_INFO, "Connect failed: %s", errmsg);
- grpc_error_free_string(errmsg);
maybe_start_connecting_locked(exec_ctx, c);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
@@ -763,7 +762,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
- grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time,
+ grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time,
gpr_timespec deadline, grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
*call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
@@ -775,7 +774,7 @@ grpc_error *grpc_connected_subchannel_create_call(
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);
- grpc_error_free_string(error_string);
+
gpr_free(*call);
return error;
}
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 684675eb37..9bd35a7704 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -114,7 +114,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call */
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
- grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time,
+ grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time,
gpr_timespec deadline, grpc_subchannel_call **subchannel_call);
/** process a transport level op */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 567e65ac69..308facb7e7 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -135,13 +135,13 @@ int grpc_lb_glb_trace = 0;
/* add lb_token of selected subchannel (address) to the call's initial
* metadata */
-static void initial_metadata_add_lb_token(
- grpc_metadata_batch *initial_metadata,
- grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem *lb_token) {
+static grpc_error *initial_metadata_add_lb_token(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *initial_metadata,
+ grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem lb_token) {
GPR_ASSERT(lb_token_mdelem_storage != NULL);
- GPR_ASSERT(lb_token != NULL);
- grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
- lb_token);
+ GPR_ASSERT(!GRPC_MDISNULL(lb_token));
+ return grpc_metadata_batch_add_tail(exec_ctx, initial_metadata,
+ lb_token_mdelem_storage, lb_token);
}
typedef struct wrapped_rr_closure_arg {
@@ -161,7 +161,7 @@ typedef struct wrapped_rr_closure_arg {
grpc_connected_subchannel **target;
/* the LB token associated with the pick */
- grpc_mdelem *lb_token;
+ grpc_mdelem lb_token;
/* storage for the lb token initial metadata mdelem */
grpc_linked_mdelem *lb_token_mdelem_storage;
@@ -188,8 +188,8 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
* addresses failed to connect). There won't be any user_data/token
* available */
if (*wc_arg->target != NULL) {
- if (wc_arg->lb_token != NULL) {
- initial_metadata_add_lb_token(wc_arg->initial_metadata,
+ if (!GRPC_MDISNULL(wc_arg->lb_token)) {
+ initial_metadata_add_lb_token(exec_ctx, wc_arg->initial_metadata,
wc_arg->lb_token_mdelem_storage,
GRPC_MDELEM_REF(wc_arg->lb_token));
} else {
@@ -345,8 +345,7 @@ typedef struct glb_lb_policy {
/* call status code and details, set in lb_on_server_status_received() */
grpc_status_code lb_call_status;
- char *lb_call_status_details;
- size_t lb_call_status_details_capacity;
+ grpc_slice lb_call_status_details;
/** LB call retry backoff state */
gpr_backoff lb_call_backoff_state;
@@ -388,10 +387,14 @@ static bool is_server_valid(const grpc_grpclb_server *server, size_t idx,
/* vtable for LB tokens in grpc_lb_addresses. */
static void *lb_token_copy(void *token) {
- return token == NULL ? NULL : GRPC_MDELEM_REF(token);
+ return token == NULL
+ ? NULL
+ : (void *)GRPC_MDELEM_REF((grpc_mdelem){(uintptr_t)token}).payload;
}
static void lb_token_destroy(grpc_exec_ctx *exec_ctx, void *token) {
- if (token != NULL) GRPC_MDELEM_UNREF(exec_ctx, token);
+ if (token != NULL) {
+ GRPC_MDELEM_UNREF(exec_ctx, (grpc_mdelem){(uintptr_t)token});
+ }
}
static int lb_token_cmp(void *token1, void *token2) {
if (token1 > token2) return 1;
@@ -459,10 +462,11 @@ static grpc_lb_addresses *process_serverlist_locked(
GPR_ARRAY_SIZE(server->load_balance_token);
const size_t lb_token_length =
strnlen(server->load_balance_token, lb_token_max_length);
- grpc_mdstr *lb_token_mdstr = grpc_mdstr_from_buffer(
- (uint8_t *)server->load_balance_token, lb_token_length);
- user_data = grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_LB_TOKEN, lb_token_mdstr);
+ grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer(
+ server->load_balance_token, lb_token_length);
+ user_data = (void *)grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN,
+ lb_token_mdstr)
+ .payload;
} else {
char *uri = grpc_sockaddr_to_uri(&addr);
gpr_log(GPR_INFO,
@@ -470,7 +474,7 @@ static grpc_lb_addresses *process_serverlist_locked(
"be used instead",
uri);
gpr_free(uri);
- user_data = GRPC_MDELEM_LB_TOKEN_EMPTY;
+ user_data = (void *)GRPC_MDELEM_LB_TOKEN_EMPTY.payload;
}
grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len,
@@ -564,7 +568,7 @@ static bool pick_from_internal_rr_locked(
GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick_sync");
/* add the load reporting initial metadata */
- initial_metadata_add_lb_token(pick_args->initial_metadata,
+ initial_metadata_add_lb_token(exec_ctx, pick_args->initial_metadata,
pick_args->lb_token_mdelem_storage,
GRPC_MDELEM_REF(wc_arg->lb_token));
@@ -1103,11 +1107,12 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx,
/* Note the following LB call progresses every time there's activity in \a
* glb_policy->base.interested_parties, which is comprised of the polling
* entities from \a client_channel. */
+ grpc_slice host = grpc_slice_from_copied_string(glb_policy->server_name);
glb_policy->lb_call = grpc_channel_create_pollset_set_call(
exec_ctx, glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
glb_policy->base.interested_parties,
- "/grpc.lb.v1.LoadBalancer/BalanceLoad", glb_policy->server_name,
- glb_policy->deadline, NULL);
+ GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD,
+ &host, glb_policy->deadline, NULL);
grpc_metadata_array_init(&glb_policy->lb_initial_metadata_recv);
grpc_metadata_array_init(&glb_policy->lb_trailing_metadata_recv);
@@ -1120,9 +1125,6 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx,
grpc_slice_unref_internal(exec_ctx, request_payload_slice);
grpc_grpclb_request_destroy(request);
- glb_policy->lb_call_status_details = NULL;
- glb_policy->lb_call_status_details_capacity = 0;
-
grpc_closure_init(&glb_policy->lb_on_server_status_received,
lb_on_server_status_received, glb_policy,
grpc_schedule_on_exec_ctx);
@@ -1138,7 +1140,8 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx,
GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
}
-static void lb_call_destroy_locked(glb_lb_policy *glb_policy) {
+static void lb_call_destroy_locked(grpc_exec_ctx *exec_ctx,
+ glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->lb_call != NULL);
grpc_call_destroy(glb_policy->lb_call);
glb_policy->lb_call = NULL;
@@ -1147,7 +1150,7 @@ static void lb_call_destroy_locked(glb_lb_policy *glb_policy) {
grpc_metadata_array_destroy(&glb_policy->lb_trailing_metadata_recv);
grpc_byte_buffer_destroy(glb_policy->lb_request_payload);
- gpr_free(glb_policy->lb_call_status_details);
+ grpc_slice_unref_internal(exec_ctx, glb_policy->lb_call_status_details);
}
/*
@@ -1197,8 +1200,6 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx,
op->data.recv_status_on_client.status = &glb_policy->lb_call_status;
op->data.recv_status_on_client.status_details =
&glb_policy->lb_call_status_details;
- op->data.recv_status_on_client.status_details_capacity =
- &glb_policy->lb_call_status_details_capacity;
op->flags = 0;
op->reserved = NULL;
op++;
@@ -1341,15 +1342,18 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(glb_policy->lb_call != NULL);
if (grpc_lb_glb_trace) {
+ char *status_details =
+ grpc_slice_to_c_string(glb_policy->lb_call_status_details);
gpr_log(GPR_DEBUG,
"Status from LB server received. Status = %d, Details = '%s', "
"(call: %p)",
- glb_policy->lb_call_status, glb_policy->lb_call_status_details,
+ glb_policy->lb_call_status, status_details,
(void *)glb_policy->lb_call);
+ gpr_free(status_details);
}
- /* We need to performe cleanups no matter what. */
- lb_call_destroy_locked(glb_policy);
+ /* We need to perform cleanups no matter what. */
+ lb_call_destroy_locked(exec_ctx, glb_policy);
if (!glb_policy->shutting_down) {
/* if we aren't shutting down, restart the LB client call after some time */
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index 07ef10e6a8..8af6191c3b 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -41,13 +41,17 @@
#include "src/core/ext/load_reporting/load_reporting_filter.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/static_metadata.h"
typedef struct call_data {
intptr_t id; /**< an id unique to the call */
- char *trailing_md_string;
- char *initial_md_string;
- const char *service_method;
+ bool have_trailing_md_string;
+ grpc_slice trailing_md_string;
+ bool have_initial_md_string;
+ grpc_slice initial_md_string;
+ bool have_service_method;
+ grpc_slice service_method;
/* stores the recv_initial_metadata op's ready closure, which we wrap with our
* own (on_initial_md_ready) in order to capture the incoming initial metadata
@@ -63,42 +67,28 @@ typedef struct channel_data {
intptr_t id; /**< an id unique to the channel */
} channel_data;
-typedef struct {
- grpc_call_element *elem;
- grpc_exec_ctx *exec_ctx;
-} recv_md_filter_args;
-
-static grpc_mdelem *recv_md_filter(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_mdelem *md) {
- recv_md_filter_args *a = user_data;
- grpc_call_element *elem = a->elem;
- call_data *calld = elem->call_data;
-
- if (md->key == GRPC_MDSTR_PATH) {
- calld->service_method = grpc_mdstr_as_c_string(md->value);
- } else if (md->key == GRPC_MDSTR_LB_TOKEN) {
- calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
- return NULL;
- }
-
- return md;
-}
-
static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
if (err == GRPC_ERROR_NONE) {
- recv_md_filter_args a;
- a.elem = elem;
- a.exec_ctx = exec_ctx;
- grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
- recv_md_filter, &a);
- if (calld->service_method == NULL) {
+ if (calld->recv_initial_metadata->idx.named.path != NULL) {
+ calld->service_method = grpc_slice_ref_internal(
+ GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md));
+ calld->have_service_method = true;
+ } else {
err =
grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header"));
}
+ if (calld->recv_initial_metadata->idx.named.lb_token != NULL) {
+ calld->initial_md_string = grpc_slice_ref_internal(
+ GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.lb_token->md));
+ calld->have_initial_md_string = true;
+ grpc_metadata_batch_remove(
+ exec_ctx, calld->recv_initial_metadata,
+ calld->recv_initial_metadata->idx.named.lb_token);
+ }
} else {
GRPC_ERROR_REF(err);
}
@@ -149,8 +139,15 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
calld->service_method};
*/
- gpr_free(calld->initial_md_string);
- gpr_free(calld->trailing_md_string);
+ if (calld->have_initial_md_string) {
+ grpc_slice_unref_internal(exec_ctx, calld->initial_md_string);
+ }
+ if (calld->have_trailing_md_string) {
+ grpc_slice_unref_internal(exec_ctx, calld->trailing_md_string);
+ }
+ if (calld->have_service_method) {
+ grpc_slice_unref_internal(exec_ctx, calld->service_method);
+ }
}
/* Constructor for channel_data */
@@ -193,19 +190,6 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
*/
}
-static grpc_mdelem *lr_trailing_md_filter(grpc_exec_ctx *exec_ctx,
- void *user_data, grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
- call_data *calld = elem->call_data;
-
- if (md->key == GRPC_MDSTR_LB_COST_BIN) {
- calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
- return NULL;
- }
-
- return md;
-}
-
static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
@@ -218,8 +202,14 @@ static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
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(exec_ctx, op->send_trailing_metadata,
- lr_trailing_md_filter, elem);
+ if (op->send_trailing_metadata->idx.named.lb_cost_bin != NULL) {
+ calld->trailing_md_string = grpc_slice_ref_internal(
+ GRPC_MDVALUE(op->send_trailing_metadata->idx.named.lb_cost_bin->md));
+ calld->have_trailing_md_string = true;
+ grpc_metadata_batch_remove(
+ exec_ctx, op->send_trailing_metadata,
+ op->send_trailing_metadata->idx.named.lb_cost_bin);
+ }
}
grpc_call_next_op(exec_ctx, elem, op);
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index bf2f4e5ee4..2c9623211b 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -187,9 +187,8 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now);
- const char *msg = grpc_error_string(error);
- gpr_log(GPR_INFO, "dns resolution failed (will retry): %s", msg);
- grpc_error_free_string(msg);
+ gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
+ grpc_error_string(error));
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
GRPC_RESOLVER_REF(&r->base, "retry-timer");
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index c146a627cb..a1365f6465 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -182,7 +182,7 @@ static grpc_resolver *sockaddr_create(grpc_exec_ctx *exec_ctx,
bool errors_found = false;
for (size_t i = 0; i < addresses->num_addresses; i++) {
grpc_uri ith_uri = *args->uri;
- char *part_str = grpc_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
+ char *part_str = grpc_slice_to_c_string(path_parts.slices[i]);
ith_uri.path = part_str;
if (!parse(&ith_uri, &addresses->addresses[i].address)) {
errors_found = true; /* GPR_TRUE */
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.c b/src/core/ext/transport/chttp2/client/chttp2_connector.c
index 013c96dc70..d0a762a280 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.c
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.c
@@ -92,19 +92,21 @@ static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx,
}
static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_connector *con) {
+ grpc_connector *con, grpc_error *why) {
chttp2_connector *c = (chttp2_connector *)con;
gpr_mu_lock(&c->mu);
c->shutdown = true;
if (c->handshake_mgr != NULL) {
- grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr);
+ grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr,
+ GRPC_ERROR_REF(why));
}
// If handshaking is not yet in progress, shutdown the endpoint.
// Otherwise, the handshaker will do this for us.
if (!c->connecting && c->endpoint != NULL) {
- grpc_endpoint_shutdown(exec_ctx, c->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(why));
}
gpr_mu_unlock(&c->mu);
+ GRPC_ERROR_UNREF(why);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
@@ -121,7 +123,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
- grpc_endpoint_shutdown(exec_ctx, args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_REF(error));
grpc_endpoint_destroy(exec_ctx, args->endpoint);
grpc_channel_args_destroy(exec_ctx, args->args);
grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
@@ -195,7 +197,9 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_closure_sched(exec_ctx, notify, error);
- if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint);
+ if (c->endpoint != NULL) {
+ grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(error));
+ }
gpr_mu_unlock(&c->mu);
chttp2_connector_unref(exec_ctx, arg);
} else {
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
index 574d1a7710..ae2c3838ed 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.c
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -101,16 +101,19 @@ static void pending_handshake_manager_remove_locked(
}
static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx,
- server_state *state) {
+ server_state *state,
+ grpc_error *why) {
pending_handshake_manager_node *prev_node = NULL;
for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
node != NULL; node = node->next) {
- grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr);
+ grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr,
+ GRPC_ERROR_REF(why));
gpr_free(prev_node);
prev_node = node;
}
gpr_free(prev_node);
state->pending_handshake_mgrs = NULL;
+ GRPC_ERROR_UNREF(why);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
@@ -121,7 +124,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
- grpc_error_free_string(error_str);
+
if (error == GRPC_ERROR_NONE && args->endpoint != NULL) {
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
@@ -129,7 +132,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
- grpc_endpoint_shutdown(exec_ctx, args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_NONE);
grpc_endpoint_destroy(exec_ctx, args->endpoint);
grpc_channel_args_destroy(exec_ctx, args->args);
grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
@@ -210,7 +213,8 @@ static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&state->mu);
grpc_closure *destroy_done = state->server_destroy_listener_done;
GPR_ASSERT(state->shutdown);
- pending_handshake_manager_shutdown_locked(exec_ctx, state);
+ pending_handshake_manager_shutdown_locked(exec_ctx, state,
+ GRPC_ERROR_REF(error));
gpr_mu_unlock(&state->mu);
// Flush queued work before destroying handshaker factory, since that
// may do a synchronous unref.
@@ -307,7 +311,7 @@ grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
const char *warning_message = grpc_error_string(err);
gpr_log(GPR_INFO, "WARNING: %s", warning_message);
- grpc_error_free_string(warning_message);
+
/* we managed to bind some addresses: continue */
}
grpc_resolved_addresses_destroy(resolved);
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index bf5026bea6..c219a7d85f 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -51,7 +51,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
if (err != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
- grpc_error_free_string(msg);
+
GRPC_ERROR_UNREF(err);
}
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index 395c79a71d..cb2b3f5502 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -94,7 +94,7 @@ done:
if (err != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
- grpc_error_free_string(msg);
+
GRPC_ERROR_UNREF(err);
}
return port_num;
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.c b/src/core/ext/transport/chttp2/transport/bin_decoder.c
index 8db36e4a7f..8c87de112e 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.c
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -157,7 +157,7 @@ grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx,
"grpc_chttp2_base64_decode has a length of %d, which is not a "
"multiple of 4.\n",
(int)input_length);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
if (input_length > 0) {
@@ -178,11 +178,11 @@ grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx,
ctx.contains_tail = false;
if (!grpc_base64_decode_partial(&ctx)) {
- char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
+ char *s = grpc_slice_to_c_string(input);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
grpc_slice_unref_internal(exec_ctx, output);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input));
@@ -204,7 +204,7 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx,
"has a tail of 1 byte.\n",
(int)input_length);
grpc_slice_unref_internal(exec_ctx, output);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) {
@@ -214,7 +214,7 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx,
(int)output_length,
(int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
grpc_slice_unref_internal(exec_ctx, output);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
ctx.input_cur = GRPC_SLICE_START_PTR(input);
@@ -224,11 +224,11 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx,
ctx.contains_tail = true;
if (!grpc_base64_decode_partial(&ctx)) {
- char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
+ char *s = grpc_slice_to_c_string(input);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
grpc_slice_unref_internal(exec_ctx, output);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input));
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.c b/src/core/ext/transport/chttp2/transport/bin_encoder.c
index af25a4352a..e301c073f3 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.c
@@ -177,8 +177,7 @@ static void enc_add1(huff_out *out, uint8_t a) {
enc_flush_some(out);
}
-grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(
- grpc_slice input) {
+grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input) {
size_t input_length = GRPC_SLICE_LENGTH(input);
size_t input_triplets = input_length / 3;
size_t tail_case = input_length % 3;
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
index 477559d0e2..0f899c8e34 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -49,7 +49,6 @@ grpc_slice grpc_chttp2_huffman_compress(grpc_slice input);
grpc_slice y = grpc_chttp2_huffman_compress(x);
grpc_slice_unref_internal(exec_ctx, x);
return y; */
-grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(
- grpc_slice input);
+grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
index bd87253ed3..59b21e3330 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
@@ -31,14 +31,11 @@
*
*/
-#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/metadata.h"
void grpc_chttp2_plugin_init(void) {
- grpc_chttp2_base64_encode_and_huffman_compress =
- grpc_chttp2_base64_encode_and_huffman_compress_impl;
grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("flowctl", &grpc_flowctl_trace);
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 68a6a2155d..fa18f5a725 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -44,9 +44,7 @@
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
-#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
-#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/http/parser.h"
@@ -55,7 +53,10 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/transport/http2_errors.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/transport_impl.h"
@@ -123,6 +124,21 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error);
+static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error);
+static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error);
+
+static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_error *error);
+static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_ping_type ping_type,
+ grpc_closure *on_initiate,
+ grpc_closure *on_complete);
+
+#define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0
+#define DEFAULT_MAX_PINGS_BETWEEN_DATA 3
+
/*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
@@ -154,16 +170,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_combiner_destroy(exec_ctx, t->combiner);
- /* callback remaining pings: they're not allowed to call into the transpot,
- and maybe they hold resources that need to be freed */
- while (t->pings.next != &t->pings) {
- grpc_chttp2_outstanding_ping *ping = t->pings.next;
- grpc_closure_sched(exec_ctx, ping->on_recv,
- GRPC_ERROR_CREATE("Transport closed"));
- ping->next->prev = ping->prev;
- ping->prev->next = ping->next;
- gpr_free(ping);
- }
+ cancel_pings(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed"));
while (t->write_cb_pool) {
grpc_chttp2_write_cb *next = t->write_cb_pool->next;
@@ -171,6 +178,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
t->write_cb_pool = next;
}
+ gpr_free(t->ping_acks);
gpr_free(t->peer_string);
gpr_free(t);
}
@@ -223,10 +231,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->is_client = is_client;
t->outgoing_window = DEFAULT_WINDOW;
t->incoming_window = DEFAULT_WINDOW;
- t->stream_lookahead = DEFAULT_WINDOW;
- t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
- t->ping_counter = 1;
- t->pings.next = t->pings.prev = &t->pings;
t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->is_first_frame = true;
grpc_connectivity_state_init(
@@ -247,6 +251,22 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->destructive_reclaimer_locked,
destructive_reclaimer_locked, t,
grpc_combiner_scheduler(t->combiner, false));
+ grpc_closure_init(&t->start_bdp_ping_locked, start_bdp_ping_locked, t,
+ grpc_combiner_scheduler(t->combiner, false));
+ grpc_closure_init(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
+ grpc_combiner_scheduler(t->combiner, false));
+
+ grpc_bdp_estimator_init(&t->bdp_estimator, t->peer_string);
+ t->last_pid_update = gpr_now(GPR_CLOCK_MONOTONIC);
+ grpc_pid_controller_init(
+ &t->pid_controller,
+ (grpc_pid_controller_args){.gain_p = 4,
+ .gain_i = 8,
+ .gain_d = 0,
+ .initial_control_value = log2(DEFAULT_WINDOW),
+ .min_control_value = -1,
+ .max_control_value = 22,
+ .integral_range = 10});
grpc_chttp2_goaway_parser_init(&t->goaway_parser);
grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
@@ -289,6 +309,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
DEFAULT_MAX_HEADER_LIST_SIZE);
+ t->ping_policy = (grpc_chttp2_repeated_ping_policy){
+ .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA,
+ .min_time_between_pings =
+ gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN),
+ };
+
if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key,
@@ -306,14 +332,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
}
} else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
- const grpc_integer_options options = {-1, 5, INT_MAX};
- const int value =
- grpc_channel_arg_get_integer(&channel_args->args[i], options);
- if (value >= 0) {
- t->stream_lookahead = (uint32_t)value;
- }
- } else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
const grpc_integer_options options = {-1, 0, INT_MAX};
const int value =
@@ -323,6 +341,19 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
(uint32_t)value);
}
} else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) {
+ t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ (grpc_integer_options){DEFAULT_MAX_PINGS_BETWEEN_DATA, 0, INT_MAX});
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) {
+ t->ping_policy.min_time_between_pings = gpr_time_from_millis(
+ grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0,
+ INT_MAX}),
+ GPR_TIMESPAN);
+ } else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
&channel_args->args[i],
@@ -333,24 +364,26 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_setting_id setting_id;
grpc_integer_options integer_options;
bool availability[2] /* server, client */;
- } settings_map[] = {
- {GRPC_ARG_MAX_CONCURRENT_STREAMS,
- GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
- {-1, 0, INT_MAX},
- {true, false}},
- {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
- GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
- {-1, 0, INT_MAX},
- {true, true}},
- {GRPC_ARG_MAX_METADATA_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
- {-1, 0, INT_MAX},
- {true, true}},
- {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
- {-1, 16384, 16777215},
- {true, true}},
- };
+ } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS,
+ GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
+ {-1, 0, INT32_MAX},
+ {true, false}},
+ {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
+ GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
+ {-1, 0, INT32_MAX},
+ {true, true}},
+ {GRPC_ARG_MAX_METADATA_SIZE,
+ GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
+ {-1, 0, INT32_MAX},
+ {true, true}},
+ {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
+ GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
+ {-1, 16384, 16777215},
+ {true, true}},
+ {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
+ GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
+ {-1, 5, INT32_MAX},
+ {true, true}}};
for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) {
if (0 == strcmp(channel_args->args[i].key,
settings_map[j].channel_arg_name)) {
@@ -373,6 +406,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
}
+ t->ping_state.pings_before_data_required =
+ t->ping_policy.max_pings_without_data;
+
grpc_chttp2_initiate_write(exec_ctx, t, false, "init");
post_benign_reclaimer(exec_ctx, t);
}
@@ -409,14 +445,14 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_error_add_child(t->close_transport_on_writes_finished, error);
return;
}
- if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
+ if (!grpc_error_has_clear_grpc_status(error)) {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE);
}
t->closed = 1;
connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(error), "close_transport");
- grpc_endpoint_shutdown(exec_ctx, t->ep);
+ grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
/* flush writable stream list to avoid dangling references */
grpc_chttp2_stream *s;
@@ -424,6 +460,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
}
end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
+ cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
@@ -474,11 +511,6 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
if (server_data) {
s->id = (uint32_t)(uintptr_t)server_data;
- s->outgoing_window = t->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->incoming_window = s->max_recv_bytes =
- t->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
*t->accepting_stream = s;
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
post_destructive_reclaimer(exec_ctx, t);
@@ -507,6 +539,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
}
grpc_chttp2_list_remove_stalled_by_transport(t, s);
+ grpc_chttp2_list_remove_stalled_by_stream(t, s);
for (int i = 0; i < STREAM_LIST_COUNT; i++) {
if (s->included[i]) {
@@ -646,13 +679,21 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
GPR_TIMER_END("grpc_chttp2_initiate_write", 0);
}
-void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, bool covered_by_poller,
- const char *reason) {
+void grpc_chttp2_become_writable(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+ grpc_chttp2_stream_write_type stream_write_type, const char *reason) {
if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) {
GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become");
- grpc_chttp2_initiate_write(exec_ctx, t, covered_by_poller, reason);
+ }
+ switch (stream_write_type) {
+ case GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK:
+ break;
+ case GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED:
+ grpc_chttp2_initiate_write(exec_ctx, t, true, reason);
+ break;
+ case GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED:
+ grpc_chttp2_initiate_write(exec_ctx, t, false, reason);
+ break;
}
}
@@ -780,7 +821,6 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
grpc_chttp2_stream *s;
- uint32_t stream_incoming_window;
/* start streams where we have free grpc_chttp2_stream ids and free
* concurrency */
while (t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
@@ -803,15 +843,11 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
"no_more_stream_ids");
}
- s->outgoing_window = t->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->incoming_window = stream_incoming_window =
- t->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes);
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
post_destructive_reclaimer(exec_ctx, t);
- grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream");
+ grpc_chttp2_become_writable(exec_ctx, t, s,
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
+ "new_stream");
}
/* cancel out streams that will never be started */
while (t->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@@ -866,7 +902,6 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
(int)(closure->next_data.scratch / CLOSURE_BARRIER_FIRST_REF_BIT),
(int)(closure->next_data.scratch % CLOSURE_BARRIER_FIRST_REF_BIT),
desc, errstr);
- grpc_error_free_string(errstr);
}
if (error != GRPC_ERROR_NONE) {
if (closure->error_data.error == GRPC_ERROR_NONE) {
@@ -895,12 +930,9 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
}
static bool contains_non_ok_status(grpc_metadata_batch *batch) {
- grpc_linked_mdelem *l;
- for (l = batch->list.head; l; l = l->next) {
- if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
- l->md != GRPC_MDELEM_GRPC_STATUS_0) {
- return true;
- }
+ if (batch->idx.named.grpc_status != NULL) {
+ return !grpc_mdelem_eq(batch->idx.named.grpc_status->md,
+ GRPC_MDELEM_GRPC_STATUS_0);
}
return false;
}
@@ -910,7 +942,9 @@ static void maybe_become_writable_due_to_send_msg(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s) {
if (s->id != 0 && (!s->write_buffering ||
s->flow_controlled_buffer.length > t->write_buffer_size)) {
- grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
+ grpc_chttp2_become_writable(exec_ctx, t, s,
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
+ "op.send_message");
}
}
@@ -980,9 +1014,12 @@ static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id,
bool is_client, bool is_initial) {
for (grpc_linked_mdelem *md = md_batch->list.head; md != md_batch->list.tail;
md = md->next) {
+ char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md));
+ char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md));
gpr_log(GPR_INFO, "HTTP:%d:%s:%s: %s: %s", id, is_initial ? "HDR" : "TRL",
- is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->md->key),
- grpc_mdstr_as_c_string(md->md->value));
+ is_client ? "CLI" : "SVR", key, value);
+ gpr_free(key);
+ gpr_free(value);
}
}
@@ -1025,11 +1062,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->cancel_error != GRPC_ERROR_NONE) {
- grpc_chttp2_cancel_stream(exec_ctx, t, s, GRPC_ERROR_REF(op->cancel_error));
- }
-
- if (op->close_error != GRPC_ERROR_NONE) {
- close_from_api(exec_ctx, t, s, GRPC_ERROR_REF(op->close_error));
+ grpc_chttp2_cancel_stream(exec_ctx, t, s, op->cancel_error);
}
if (op->send_initial_metadata != NULL) {
@@ -1073,15 +1106,17 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
} else {
GPR_ASSERT(s->id != 0);
- grpc_chttp2_become_writable(exec_ctx, t, s, true,
+ grpc_chttp2_become_writable(exec_ctx, t, s,
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
"op.send_initial_metadata");
}
} else {
s->send_initial_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->send_initial_metadata_finished,
- GRPC_ERROR_CREATE(
- "Attempt to send initial metadata after stream was closed"),
+ GRPC_ERROR_CREATE_REFERENCING(
+ "Attempt to send initial metadata after stream was closed",
+ &s->write_closed_error, 1),
"send_initial_metadata_finished");
}
}
@@ -1093,7 +1128,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (s->write_closed) {
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->fetching_send_message_finished,
- GRPC_ERROR_CREATE("Attempt to send message after stream was closed"),
+ GRPC_ERROR_CREATE_REFERENCING(
+ "Attempt to send message after stream was closed",
+ &s->write_closed_error, 1),
"fetching_send_message_finished");
} else {
GPR_ASSERT(s->fetching_send_message == NULL);
@@ -1161,7 +1198,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} else if (s->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */
- grpc_chttp2_become_writable(exec_ctx, t, s, true,
+ grpc_chttp2_become_writable(exec_ctx, t, s,
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
"op.send_trailing_metadata");
}
}
@@ -1180,8 +1218,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
s->recv_message = op->recv_message;
if (s->id != 0 &&
(s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) {
- incoming_byte_stream_update_flow_control(exec_ctx, t, s,
- t->stream_lookahead, 0);
+ incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, 0);
}
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
}
@@ -1225,51 +1262,59 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
GPR_TIMER_END("perform_stream_op", 0);
}
+static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_error *error) {
+ /* callback remaining pings: they're not allowed to call into the transpot,
+ and maybe they hold resources that need to be freed */
+ for (size_t i = 0; i < GRPC_CHTTP2_PING_TYPE_COUNT; i++) {
+ grpc_chttp2_ping_queue *pq = &t->ping_queues[i];
+ for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) {
+ grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
+ grpc_closure_list_sched(exec_ctx, &pq->lists[j]);
+ }
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_closure *on_recv) {
- grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
- p->next = &t->pings;
- p->prev = p->next->prev;
- p->prev->next = p->next->prev = p;
- p->id[0] = (uint8_t)((t->ping_counter >> 56) & 0xff);
- p->id[1] = (uint8_t)((t->ping_counter >> 48) & 0xff);
- p->id[2] = (uint8_t)((t->ping_counter >> 40) & 0xff);
- p->id[3] = (uint8_t)((t->ping_counter >> 32) & 0xff);
- p->id[4] = (uint8_t)((t->ping_counter >> 24) & 0xff);
- p->id[5] = (uint8_t)((t->ping_counter >> 16) & 0xff);
- p->id[6] = (uint8_t)((t->ping_counter >> 8) & 0xff);
- p->id[7] = (uint8_t)(t->ping_counter & 0xff);
- t->ping_counter++;
- p->on_recv = on_recv;
- grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
- grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping");
+ grpc_chttp2_ping_type ping_type,
+ grpc_closure *on_initiate, grpc_closure *on_ack) {
+ grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type];
+ grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate,
+ GRPC_ERROR_NONE);
+ if (grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT], on_ack,
+ GRPC_ERROR_NONE)) {
+ grpc_chttp2_initiate_write(exec_ctx, t, false, "send_ping");
+ }
}
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- const uint8_t *opaque_8bytes) {
- grpc_chttp2_outstanding_ping *ping;
- for (ping = t->pings.next; ping != &t->pings; ping = ping->next) {
- if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
- grpc_closure_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE);
- ping->next->prev = ping->prev;
- ping->prev->next = ping->next;
- gpr_free(ping);
- return;
- }
+ uint64_t id) {
+ grpc_chttp2_ping_queue *pq =
+ &t->ping_queues[id % GRPC_CHTTP2_PING_TYPE_COUNT];
+ if (pq->inflight_id != id) {
+ char *from = grpc_endpoint_get_peer(t->ep);
+ gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, from, id);
+ gpr_free(from);
+ return;
+ }
+ grpc_closure_list_sched(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]);
+ if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) {
+ grpc_chttp2_initiate_write(exec_ctx, t, false, "continue_pings");
}
- char *msg = gpr_dump((const char *)opaque_8bytes, 8, GPR_DUMP_HEX);
- char *from = grpc_endpoint_get_peer(t->ep);
- gpr_log(GPR_DEBUG, "Unknown ping response from %s: %s", from, msg);
- gpr_free(from);
- gpr_free(msg);
}
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;
- grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data,
- &t->qbuf);
+ grpc_http2_error_code http_error;
+ 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_ERROR_UNREF(error);
}
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
@@ -1285,10 +1330,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
op->on_connectivity_state_change);
}
- if (op->send_goaway) {
- send_goaway(exec_ctx, t,
- grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
- grpc_slice_ref_internal(*op->goaway_message));
+ if (op->goaway_error) {
+ send_goaway(exec_ctx, t, op->goaway_error);
}
if (op->set_accept_stream) {
@@ -1306,7 +1349,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
}
if (op->send_ping) {
- send_ping_locked(exec_ctx, t, op->send_ping);
+ send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, NULL,
+ op->send_ping);
}
if (close_transport != GRPC_ERROR_NONE) {
@@ -1348,8 +1392,8 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
}
}
- grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[0],
- s->recv_initial_metadata);
+ grpc_chttp2_incoming_metadata_buffer_publish(
+ exec_ctx, &s->metadata_buffer[0], s->recv_initial_metadata);
null_then_run_closure(exec_ctx, &s->recv_initial_metadata_ready,
GRPC_ERROR_NONE);
}
@@ -1392,8 +1436,8 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
}
if (s->all_incoming_byte_streams_finished &&
s->recv_trailing_metadata_finished != NULL) {
- grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1],
- s->recv_trailing_metadata);
+ grpc_chttp2_incoming_metadata_buffer_publish(
+ exec_ctx, &s->metadata_buffer[1], s->recv_trailing_metadata);
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE,
"recv_trailing_metadata_finished");
@@ -1441,70 +1485,37 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *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,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_error *due_to_error) {
- 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 (!t->is_client && !s->sent_trailing_metadata &&
+ grpc_error_has_clear_grpc_status(due_to_error)) {
+ close_from_api(exec_ctx, t, s, due_to_error);
+ return;
+ }
+ if (!s->read_closed || !s->write_closed) {
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(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
&s->stats.outgoing));
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) {
s->seen_error = true;
- grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, due_to_error);
}
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, grpc_status_code status,
- grpc_slice *slice) {
+ grpc_chttp2_stream *s, grpc_error *error) {
+ grpc_status_code status;
+ const char *msg;
+ grpc_error_get_status(error, s->deadline, &status, &msg, NULL);
+
if (status != GRPC_STATUS_OK) {
s->seen_error = true;
}
@@ -1518,24 +1529,21 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
s->recv_trailing_metadata_finished != NULL) {
char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string);
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->metadata_buffer[1], grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_STATUS,
- grpc_mdstr_from_string(status_string)));
- if (slice) {
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->metadata_buffer[1],
- grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_mdstr_from_slice(exec_ctx,
- grpc_slice_ref_internal(*slice))));
+ grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ exec_ctx, &s->metadata_buffer[1],
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
+ grpc_slice_from_copied_string(status_string)));
+ if (msg != NULL) {
+ grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ exec_ctx, &s->metadata_buffer[1],
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_slice_from_copied_string(msg)));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
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) {
@@ -1601,36 +1609,48 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
int close_writes, grpc_error *error) {
if (s->read_closed && s->write_closed) {
/* already closed */
+ grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
GRPC_ERROR_UNREF(error);
return;
}
+ bool closed_read = false;
+ bool became_closed = false;
if (close_reads && !s->read_closed) {
s->read_closed_error = GRPC_ERROR_REF(error);
s->read_closed = true;
- for (int i = 0; i < 2; i++) {
- if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
- s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
- }
- }
- decrement_active_streams_locked(exec_ctx, t, s);
- grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
- grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
- grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
+ closed_read = true;
}
if (close_writes && !s->write_closed) {
s->write_closed_error = GRPC_ERROR_REF(error);
s->write_closed = true;
grpc_chttp2_fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
- grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
if (s->read_closed && s->write_closed) {
+ became_closed = true;
+ grpc_error *overall_error =
+ removal_error(GRPC_ERROR_REF(error), s, "Stream removed");
if (s->id != 0) {
- remove_stream(exec_ctx, t, s->id,
- removal_error(GRPC_ERROR_REF(error), s, "Stream removed"));
+ remove_stream(exec_ctx, t, s->id, GRPC_ERROR_REF(overall_error));
} else {
/* Purge streams waiting on concurrency still waiting for id assignment */
grpc_chttp2_list_remove_waiting_for_concurrency(t, s);
}
+ if (overall_error != GRPC_ERROR_NONE) {
+ grpc_chttp2_fake_status(exec_ctx, t, s, overall_error);
+ }
+ }
+ if (closed_read) {
+ for (int i = 0; i < 2; i++) {
+ if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
+ s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
+ }
+ }
+ decrement_active_streams_locked(exec_ctx, t, s);
+ grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
+ grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+ }
+ if (became_closed) {
+ grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2");
}
GRPC_ERROR_UNREF(error);
@@ -1644,112 +1664,92 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint8_t *p;
uint32_t len = 0;
grpc_status_code grpc_status;
- grpc_chttp2_error_code http_error;
- status_codes_from_error(error, s->deadline, &http_error, &grpc_status);
+ const char *msg;
+ grpc_error_get_status(error, s->deadline, &grpc_status, &msg, NULL);
GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
- if (s->id != 0 && !t->is_client) {
- /* Hand roll a header block.
- This is unnecessarily ugly - at some point we should find a more
- elegant
- solution.
- It's complicated by the fact that our send machinery would be dead by
- the
- time we got around to sending this, so instead we ignore HPACK
- compression
- and just write the uncompressed bytes onto the wire. */
- status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
- p = GRPC_SLICE_START_PTR(status_hdr);
- *p++ = 0x40; /* literal header */
- *p++ = 11; /* len(grpc-status) */
+ /* Hand roll a header block.
+ This is unnecessarily ugly - at some point we should find a more
+ elegant solution.
+ It's complicated by the fact that our send machinery would be dead by
+ the time we got around to sending this, so instead we ignore HPACK
+ compression and just write the uncompressed bytes onto the wire. */
+ status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
+ p = GRPC_SLICE_START_PTR(status_hdr);
+ *p++ = 0x00; /* literal header, not indexed */
+ *p++ = 11; /* len(grpc-status) */
+ *p++ = 'g';
+ *p++ = 'r';
+ *p++ = 'p';
+ *p++ = 'c';
+ *p++ = '-';
+ *p++ = 's';
+ *p++ = 't';
+ *p++ = 'a';
+ *p++ = 't';
+ *p++ = 'u';
+ *p++ = 's';
+ if (grpc_status < 10) {
+ *p++ = 1;
+ *p++ = (uint8_t)('0' + grpc_status);
+ } else {
+ *p++ = 2;
+ *p++ = (uint8_t)('0' + (grpc_status / 10));
+ *p++ = (uint8_t)('0' + (grpc_status % 10));
+ }
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
+ len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
+
+ if (msg != NULL) {
+ size_t msg_len = strlen(msg);
+ GPR_ASSERT(msg_len <= UINT32_MAX);
+ uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
+ message_pfx = grpc_slice_malloc(14 + msg_len_len);
+ p = GRPC_SLICE_START_PTR(message_pfx);
+ *p++ = 0x00; /* literal header, not indexed */
+ *p++ = 12; /* len(grpc-message) */
*p++ = 'g';
*p++ = 'r';
*p++ = 'p';
*p++ = 'c';
*p++ = '-';
+ *p++ = 'm';
+ *p++ = 'e';
*p++ = 's';
- *p++ = 't';
- *p++ = 'a';
- *p++ = 't';
- *p++ = 'u';
*p++ = 's';
- if (grpc_status < 10) {
- *p++ = 1;
- *p++ = (uint8_t)('0' + grpc_status);
- } else {
- *p++ = 2;
- *p++ = (uint8_t)('0' + (grpc_status / 10));
- *p++ = (uint8_t)('0' + (grpc_status % 10));
- }
- GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
- len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
-
- const char *optional_message =
- grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
-
- if (optional_message != NULL) {
- size_t msg_len = strlen(optional_message);
- GPR_ASSERT(msg_len <= UINT32_MAX);
- uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
- message_pfx = grpc_slice_malloc(14 + msg_len_len);
- p = GRPC_SLICE_START_PTR(message_pfx);
- *p++ = 0x40;
- *p++ = 12; /* len(grpc-message) */
- *p++ = 'g';
- *p++ = 'r';
- *p++ = 'p';
- *p++ = 'c';
- *p++ = '-';
- *p++ = 'm';
- *p++ = 'e';
- *p++ = 's';
- *p++ = 's';
- *p++ = 'a';
- *p++ = 'g';
- *p++ = 'e';
- GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p,
- (uint32_t)msg_len_len);
- p += msg_len_len;
- GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
- len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
- len += (uint32_t)msg_len;
- }
-
- hdr = grpc_slice_malloc(9);
- p = GRPC_SLICE_START_PTR(hdr);
- *p++ = (uint8_t)(len >> 16);
- *p++ = (uint8_t)(len >> 8);
- *p++ = (uint8_t)(len);
- *p++ = GRPC_CHTTP2_FRAME_HEADER;
- *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
- *p++ = (uint8_t)(s->id >> 24);
- *p++ = (uint8_t)(s->id >> 16);
- *p++ = (uint8_t)(s->id >> 8);
- *p++ = (uint8_t)(s->id);
- GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
-
- grpc_slice_buffer_add(&t->qbuf, hdr);
- grpc_slice_buffer_add(&t->qbuf, status_hdr);
- if (optional_message) {
- grpc_slice_buffer_add(&t->qbuf, message_pfx);
- grpc_slice_buffer_add(&t->qbuf,
- grpc_slice_from_copied_string(optional_message));
- }
- grpc_slice_buffer_add(
- &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
- &s->stats.outgoing));
- }
-
- const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
- bool free_msg = false;
- if (msg == NULL) {
- free_msg = true;
- msg = grpc_error_string(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);
+ *p++ = 'a';
+ *p++ = 'g';
+ *p++ = 'e';
+ GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, (uint32_t)msg_len_len);
+ p += msg_len_len;
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
+ len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
+ len += (uint32_t)msg_len;
+ }
+
+ hdr = grpc_slice_malloc(9);
+ p = GRPC_SLICE_START_PTR(hdr);
+ *p++ = (uint8_t)(len >> 16);
+ *p++ = (uint8_t)(len >> 8);
+ *p++ = (uint8_t)(len);
+ *p++ = GRPC_CHTTP2_FRAME_HEADER;
+ *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
+ *p++ = (uint8_t)(s->id >> 24);
+ *p++ = (uint8_t)(s->id >> 16);
+ *p++ = (uint8_t)(s->id >> 8);
+ *p++ = (uint8_t)(s->id);
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
+
+ grpc_slice_buffer_add(&t->qbuf, hdr);
+ grpc_slice_buffer_add(&t->qbuf, status_hdr);
+ if (msg != NULL) {
+ grpc_slice_buffer_add(&t->qbuf, message_pfx);
+ grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg));
+ }
+ grpc_slice_buffer_add(
+ &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
+ &s->stats.outgoing));
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error);
grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api");
@@ -1775,34 +1775,28 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GRPC_ERROR_UNREF(error);
}
-/** update window from a settings change */
-typedef struct {
- grpc_chttp2_transport *t;
- grpc_exec_ctx *exec_ctx;
-} update_global_window_args;
+/*******************************************************************************
+ * INPUT PROCESSING - PARSING
+ */
-static void update_global_window(void *args, uint32_t id, void *stream) {
- update_global_window_args *a = args;
- grpc_chttp2_transport *t = a->t;
- grpc_chttp2_stream *s = stream;
- int was_zero;
- int is_zero;
- int64_t initial_window_update = t->initial_window_update;
-
- if (initial_window_update > 0) {
- was_zero = s->outgoing_window <= 0;
- GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", t, s, outgoing_window,
- initial_window_update);
- is_zero = s->outgoing_window <= 0;
-
- if (was_zero && !is_zero) {
- grpc_chttp2_become_writable(a->exec_ctx, t, s, true,
- "update_global_window");
- }
+static void update_bdp(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ double bdp_dbl) {
+ uint32_t bdp;
+ if (bdp_dbl <= 0) {
+ bdp = 0;
+ } else if (bdp_dbl > UINT32_MAX) {
+ bdp = UINT32_MAX;
} else {
- GRPC_CHTTP2_FLOW_DEBIT_STREAM("settings", t, s, outgoing_window,
- -initial_window_update);
+ bdp = (uint32_t)(bdp_dbl);
}
+ int64_t delta =
+ (int64_t)bdp -
+ (int64_t)t->settings[GRPC_LOCAL_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+ if (delta == 0 || (bdp != 0 && delta > -1024 && delta < 1024)) {
+ return;
+ }
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, bdp);
}
/*******************************************************************************
@@ -1827,8 +1821,10 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
if (parse_error == GRPC_ERROR_NONE &&
(parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
error = grpc_error_set_int(
- GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
- GRPC_ERROR_INT_HTTP_STATUS, response.status);
+ grpc_error_set_int(
+ GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
+ GRPC_ERROR_INT_HTTP_STATUS, response.status),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
}
GRPC_ERROR_UNREF(parse_error);
@@ -1842,6 +1838,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_BEGIN("reading_action_locked", 0);
grpc_chttp2_transport *t = tp;
+ bool need_bdp_ping = false;
GRPC_ERROR_REF(error);
@@ -1859,9 +1856,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
GRPC_ERROR_NONE};
for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
+ if (grpc_bdp_estimator_add_incoming_bytes(
+ &t->bdp_estimator,
+ (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]))) {
+ need_bdp_ping = true;
+ }
errors[1] =
grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]);
- };
+ }
if (errors[1] != GRPC_ERROR_NONE) {
errors[2] = try_http_parsing(exec_ctx, t);
GRPC_ERROR_UNREF(error);
@@ -1875,21 +1877,16 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_BEGIN("post_parse_locked", 0);
if (t->initial_window_update != 0) {
- update_global_window_args args = {t, exec_ctx};
- grpc_chttp2_stream_map_for_each(&t->stream_map, update_global_window,
- &args);
+ if (t->initial_window_update > 0) {
+ grpc_chttp2_stream *s;
+ while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) {
+ grpc_chttp2_become_writable(
+ exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED,
+ "unstalled");
+ }
+ }
t->initial_window_update = 0;
}
- /* handle higher level things */
- if (t->incoming_window < t->connection_window_target * 3 / 4) {
- int64_t announce_bytes = t->connection_window_target - t->incoming_window;
- GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, announce_incoming_window,
- announce_bytes);
- GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, incoming_window,
- announce_bytes);
- grpc_chttp2_initiate_write(exec_ctx, t, false, "global incoming window");
- }
-
GPR_TIMER_END("post_parse_locked", 0);
}
@@ -1910,6 +1907,35 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (keep_reading) {
grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer,
&t->read_action_locked);
+
+ if (need_bdp_ping) {
+ GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
+ grpc_bdp_estimator_schedule_ping(&t->bdp_estimator);
+ send_ping_locked(exec_ctx, t,
+ GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE,
+ &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked);
+ }
+
+ int64_t estimate = -1;
+ if (grpc_bdp_estimator_get_estimate(&t->bdp_estimator, &estimate)) {
+ double target = 1 + log2((double)estimate);
+ double memory_pressure = grpc_resource_quota_get_memory_pressure(
+ grpc_resource_user_quota(grpc_endpoint_get_resource_user(t->ep)));
+ if (memory_pressure > 0.8) {
+ target *= 1 - GPR_MIN(1, (memory_pressure - 0.8) / 0.1);
+ }
+ double bdp_error = target - grpc_pid_controller_last(&t->pid_controller);
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ gpr_timespec dt_timespec = gpr_time_sub(now, t->last_pid_update);
+ double dt = (double)dt_timespec.tv_sec + dt_timespec.tv_nsec * 1e-9;
+ if (dt > 0.1) {
+ dt = 0.1;
+ }
+ double log2_bdp_guess =
+ grpc_pid_controller_update(&t->pid_controller, bdp_error, dt);
+ update_bdp(exec_ctx, t, pow(2, log2_bdp_guess));
+ t->last_pid_update = now;
+ }
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
} else {
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action");
@@ -1922,6 +1948,26 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_END("reading_action_locked", 0);
}
+static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = tp;
+ if (grpc_http_trace) {
+ gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string);
+ }
+ grpc_bdp_estimator_start_ping(&t->bdp_estimator);
+}
+
+static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = tp;
+ if (grpc_http_trace) {
+ gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string);
+ }
+ grpc_bdp_estimator_complete_ping(&t->bdp_estimator);
+
+ GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
+}
+
/*******************************************************************************
* CALLBACK LOOP
*/
@@ -1972,10 +2018,12 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
size_t max_size_hint,
size_t have_already) {
uint32_t max_recv_bytes;
+ uint32_t initial_window_size =
+ t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
/* clamp max recv hint to an allowable size */
- if (max_size_hint >= UINT32_MAX - t->stream_lookahead) {
- max_recv_bytes = UINT32_MAX - t->stream_lookahead;
+ if (max_size_hint >= UINT32_MAX - initial_window_size) {
+ max_recv_bytes = UINT32_MAX - initial_window_size;
} else {
max_recv_bytes = (uint32_t)max_size_hint;
}
@@ -1988,20 +2036,26 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
}
/* add some small lookahead to keep pipelines flowing */
- GPR_ASSERT(max_recv_bytes <= UINT32_MAX - t->stream_lookahead);
- max_recv_bytes += t->stream_lookahead;
- if (s->max_recv_bytes < max_recv_bytes) {
- uint32_t add_max_recv_bytes = max_recv_bytes - s->max_recv_bytes;
- bool new_window_write_is_covered_by_poller =
- s->max_recv_bytes < have_already;
- GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, max_recv_bytes,
- add_max_recv_bytes);
- GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window,
+ GPR_ASSERT(max_recv_bytes <= UINT32_MAX - initial_window_size);
+ if (s->incoming_window_delta < max_recv_bytes && !s->read_closed) {
+ uint32_t add_max_recv_bytes =
+ (uint32_t)(max_recv_bytes - s->incoming_window_delta);
+ grpc_chttp2_stream_write_type write_type =
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED;
+ if (s->incoming_window_delta + initial_window_size <
+ (int64_t)have_already) {
+ write_type = GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED;
+ }
+ GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window_delta,
add_max_recv_bytes);
GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, announce_window,
add_max_recv_bytes);
- grpc_chttp2_become_writable(exec_ctx, t, s,
- new_window_write_is_covered_by_poller,
+ if ((int64_t)s->incoming_window_delta + (int64_t)initial_window_size -
+ (int64_t)s->announce_window >
+ (int64_t)initial_window_size / 2) {
+ write_type = GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK;
+ }
+ grpc_chttp2_become_writable(exec_ctx, t, s, write_type,
"read_incoming_stream");
}
}
@@ -2089,6 +2143,8 @@ static void incoming_byte_stream_publish_error(
grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error));
bs->on_next = NULL;
GRPC_ERROR_UNREF(bs->error);
+ grpc_chttp2_cancel_stream(exec_ctx, bs->transport, bs->stream,
+ GRPC_ERROR_REF(error));
bs->error = error;
}
@@ -2197,8 +2253,10 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory",
t->peer_string);
}
- send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM,
- grpc_slice_from_static_string("Buffers full"));
+ send_goaway(exec_ctx, t,
+ 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) {
gpr_log(GPR_DEBUG,
"HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
@@ -2227,7 +2285,7 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_cancel_stream(
exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR,
- GRPC_CHTTP2_ENHANCE_YOUR_CALM));
+ GRPC_HTTP2_ENHANCE_YOUR_CALM));
if (n > 1) {
/* Since we cancel one stream per destructive reclamation, if
there are more streams left, we can immediately post a new
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 7de5f6362d..f487533c41 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -40,7 +40,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
+grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) {
grpc_slice slice = grpc_slice_malloc(9 + 8);
uint8_t *p = GRPC_SLICE_START_PTR(slice);
@@ -53,7 +53,14 @@ grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
*p++ = 0;
*p++ = 0;
*p++ = 0;
- memcpy(p, opaque_8bytes, 8);
+ *p++ = (uint8_t)(opaque_8bytes >> 56);
+ *p++ = (uint8_t)(opaque_8bytes >> 48);
+ *p++ = (uint8_t)(opaque_8bytes >> 40);
+ *p++ = (uint8_t)(opaque_8bytes >> 32);
+ *p++ = (uint8_t)(opaque_8bytes >> 24);
+ *p++ = (uint8_t)(opaque_8bytes >> 16);
+ *p++ = (uint8_t)(opaque_8bytes >> 8);
+ *p++ = (uint8_t)(opaque_8bytes);
return slice;
}
@@ -70,6 +77,7 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
}
parser->byte = 0;
parser->is_ack = flags;
+ parser->opaque_8bytes = 0;
return GRPC_ERROR_NONE;
}
@@ -83,7 +91,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_ping_parser *p = parser;
while (p->byte != 8 && cur != end) {
- p->opaque_8bytes[p->byte] = *cur;
+ p->opaque_8bytes |= (((uint64_t)*cur) << (8 * p->byte));
cur++;
p->byte++;
}
@@ -93,8 +101,12 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
if (p->is_ack) {
grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
} else {
- grpc_slice_buffer_add(&t->qbuf,
- grpc_chttp2_ping_create(1, p->opaque_8bytes));
+ if (t->ping_ack_count == t->ping_ack_capacity) {
+ t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
+ t->ping_acks = gpr_realloc(
+ t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks));
+ }
+ t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes;
grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
}
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index b9889e2d11..ef642465d7 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -41,10 +41,10 @@
typedef struct {
uint8_t byte;
uint8_t is_ack;
- uint8_t opaque_8bytes[8];
+ uint64_t opaque_8bytes;
} grpc_chttp2_ping_parser;
-grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
+grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes);
grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
uint32_t length, uint8_t flags);
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index 20043f5fbf..7d5beed09d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -39,8 +39,7 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.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/transport/http2_errors.h"
grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
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[3]));
grpc_error *error = GRPC_ERROR_NONE;
- if (reason != GRPC_CHTTP2_NO_ERROR || s->header_frames_received < 2) {
+ if (reason != GRPC_HTTP2_NO_ERROR || s->header_frames_received < 2) {
error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"),
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);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index 98facae87f..82290e34cd 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -43,8 +43,8 @@
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/transport/http2_errors.h"
#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024)
@@ -52,21 +52,21 @@
const grpc_chttp2_setting_parameters
grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
- GRPC_CHTTP2_PROTOCOL_ERROR},
+ GRPC_HTTP2_PROTOCOL_ERROR},
{"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,
- GRPC_CHTTP2_PROTOCOL_ERROR},
+ GRPC_HTTP2_PROTOCOL_ERROR},
{"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,
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
- GRPC_CHTTP2_FLOW_CONTROL_ERROR},
+ GRPC_HTTP2_FLOW_CONTROL_ERROR},
{"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_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) {
@@ -236,7 +236,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
}
if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
parser->incoming_settings[parser->id] != parser->value) {
- t->initial_window_update =
+ t->initial_window_update +=
(int64_t)parser->value - parser->incoming_settings[parser->id];
if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "adding %d for initial_window change",
@@ -245,8 +245,9 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
}
parser->incoming_settings[parser->id] = parser->value;
if (grpc_http_trace) {
- gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
- t->is_client ? "CLI" : "SVR", parser->id, parser->value);
+ gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %d = %d",
+ t->is_client ? "CLI" : "SVR", t->peer_string, parser->id,
+ parser->value);
}
} else if (grpc_http_trace) {
gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c
index 31a31c2871..8fa0bb471a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.c
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -110,13 +110,12 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
if (t->incoming_stream_id != 0) {
if (s != NULL) {
- bool was_zero = s->outgoing_window <= 0;
- GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window,
+ GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window_delta,
received_update);
- bool is_zero = s->outgoing_window <= 0;
- if (was_zero && !is_zero) {
- grpc_chttp2_become_writable(exec_ctx, t, s, false,
- "stream.read_flow_control");
+ if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) {
+ grpc_chttp2_become_writable(
+ exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED,
+ "stream.read_flow_control");
}
}
} else {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 49a8326f62..63df8e135f 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -49,6 +49,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
@@ -64,6 +65,10 @@
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
+static grpc_slice_refcount terminal_slice_refcount = {NULL, NULL};
+static const grpc_slice terminal_slice = {&terminal_slice_refcount,
+ .data.refcounted = {0, 0}};
+
extern int grpc_http_trace;
typedef struct {
@@ -185,9 +190,12 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) {
/* add an element to the decoder table */
static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
- grpc_mdelem *elem) {
- uint32_t key_hash = elem->key->hash;
- uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
+ grpc_mdelem elem) {
+ GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
+
+ uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
+ uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
+ uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
@@ -212,17 +220,18 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
c->table_elems++;
/* Store this element into {entries,indices}_elem */
- if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
+ } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
+ elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
+ } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
/* not there, but a free element: add */
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
+ } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) {
/* not there (cuckoo), but a free element: add */
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
@@ -241,24 +250,34 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
/* do exactly the same for the key (so we can find by that again too) */
- if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
+ if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
+ GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
- } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) {
+ } else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
+ GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
- } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) {
- c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
+ } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
+ &terminal_slice_refcount) {
+ c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
- } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) {
- c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
+ } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)].refcount ==
+ &terminal_slice_refcount) {
+ c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
- GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
- c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
+ grpc_slice_unref_internal(exec_ctx,
+ c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
+ c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else {
- GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
- c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
+ grpc_slice_unref_internal(exec_ctx,
+ c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
+ c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
}
}
@@ -270,20 +289,18 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
len);
}
-static grpc_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
- if (grpc_is_binary_header(
- (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
- GRPC_SLICE_LENGTH(elem->key->slice))) {
+static grpc_slice get_wire_value(grpc_mdelem elem, uint8_t *huffman_prefix) {
+ if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
*huffman_prefix = 0x80;
- return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
+ return grpc_chttp2_base64_encode_and_huffman_compress(GRPC_MDVALUE(elem));
}
/* TODO(ctiller): opportunistically compress non-binary headers */
*huffman_prefix = 0x00;
- return elem->value->slice;
+ return grpc_slice_ref_internal(GRPC_MDVALUE(elem));
}
static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
- uint32_t key_index, grpc_mdelem *elem,
+ uint32_t key_index, grpc_mdelem elem,
framer_state *st) {
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
uint8_t huffman_prefix;
@@ -296,11 +313,11 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
add_tiny_header_data(st, len_pfx), len_pfx);
GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, grpc_slice_ref_internal(value_slice));
+ add_header_data(st, value_slice);
}
static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
- uint32_t key_index, grpc_mdelem *elem,
+ uint32_t key_index, grpc_mdelem elem,
framer_state *st) {
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
uint8_t huffman_prefix;
@@ -313,12 +330,12 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
add_tiny_header_data(st, len_pfx), len_pfx);
GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, grpc_slice_ref_internal(value_slice));
+ add_header_data(st, value_slice);
}
static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
- grpc_mdelem *elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice);
+ grpc_mdelem elem, framer_state *st) {
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
uint8_t huffman_prefix;
grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
@@ -329,15 +346,15 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
*add_tiny_header_data(st, 1) = 0x40;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, grpc_slice_ref_internal(elem->key->slice));
+ add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, grpc_slice_ref_internal(value_slice));
+ add_header_data(st, value_slice);
}
static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
- grpc_mdelem *elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice);
+ grpc_mdelem elem, framer_state *st) {
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
uint8_t huffman_prefix;
grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
@@ -348,10 +365,10 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
*add_tiny_header_data(st, 1) = 0x00;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, grpc_slice_ref_internal(elem->key->slice));
+ add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, grpc_slice_ref_internal(value_slice));
+ add_header_data(st, value_slice);
}
static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
@@ -369,15 +386,9 @@ static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) {
/* encode an mdelem */
static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
- grpc_mdelem *elem, framer_state *st) {
- uint32_t key_hash = elem->key->hash;
- uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
- size_t decoder_space_usage;
- uint32_t indices_key;
- int should_add_elem;
-
- GPR_ASSERT(GRPC_SLICE_LENGTH(elem->key->slice) > 0);
- if (GRPC_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
+ grpc_mdelem elem, framer_state *st) {
+ GPR_ASSERT(GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)) > 0);
+ if (GRPC_SLICE_START_PTR(GRPC_MDKEY(elem))[0] != ':') { /* regular header */
st->seen_regular_header = 1;
} else {
GPR_ASSERT(
@@ -385,11 +396,39 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
"Reserved header (colon-prefixed) happening after regular ones.");
}
+ if (grpc_http_trace && !GRPC_MDELEM_IS_INTERNED(elem)) {
+ char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
+ char *v = grpc_slice_to_c_string(GRPC_MDVALUE(elem));
+ gpr_log(
+ GPR_DEBUG,
+ "Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",
+ k, v, GRPC_MDELEM_IS_INTERNED(elem), GRPC_MDELEM_STORAGE(elem),
+ grpc_slice_is_interned(GRPC_MDKEY(elem)),
+ grpc_slice_is_interned(GRPC_MDVALUE(elem)));
+ gpr_free(k);
+ gpr_free(v);
+ }
+ if (!GRPC_MDELEM_IS_INTERNED(elem)) {
+ emit_lithdr_noidx_v(c, elem, st);
+ return;
+ }
+
+ uint32_t key_hash;
+ uint32_t value_hash;
+ uint32_t elem_hash;
+ size_t decoder_space_usage;
+ uint32_t indices_key;
+ int should_add_elem;
+
+ key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
+ value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
+ elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
+
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
/* is this elem currently in the decoders table? */
- if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
@@ -397,7 +436,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
return;
}
- if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
@@ -414,7 +453,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
/* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
- if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
+ if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
+ GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
@@ -429,7 +469,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
- if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
+ if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
+ GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
@@ -463,11 +504,11 @@ static void deadline_enc(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
framer_state *st) {
char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
- grpc_mdelem *mdelem;
+ grpc_mdelem mdelem;
grpc_http2_encode_timeout(
gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
- mdelem = grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
+ mdelem = grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT,
+ grpc_slice_from_copied_string(timeout_str));
hpack_enc(exec_ctx, c, mdelem, st);
GRPC_MDELEM_UNREF(exec_ctx, mdelem);
}
@@ -484,14 +525,19 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
memset(c->table_elem_size, 0,
sizeof(*c->table_elem_size) * c->cap_table_elems);
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(c->entries_keys); i++) {
+ c->entries_keys[i] = terminal_slice;
+ }
}
void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c) {
int i;
for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
- if (c->entries_keys[i]) GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[i]);
- if (c->entries_elems[i]) GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]);
+ if (c->entries_keys[i].refcount != &terminal_slice_refcount) {
+ grpc_slice_unref_internal(exec_ctx, c->entries_keys[i]);
+ }
+ GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]);
}
gpr_free(c->table_elem_size);
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index 3a35496ec8..83ba5b1b3e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -74,8 +74,8 @@ typedef struct {
/* entry tables for keys & elems: these tables track values that have been
seen and *may* be in the decompressor table */
- grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
- grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+ grpc_slice entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+ grpc_mdelem entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 8b91cc760b..40f5120308 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -50,9 +50,13 @@
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
-#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/http2_errors.h"
+
+/* TODO(ctiller): remove before submission */
+#include "src/core/lib/slice/slice_string_helpers.h"
extern int grpc_http_trace;
@@ -668,8 +672,22 @@ static const uint8_t inverse_base64[256] = {
/* emission helpers */
static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
- grpc_mdelem *md, int add_to_table) {
+ grpc_mdelem md, int add_to_table) {
+ if (grpc_http_trace && !GRPC_MDELEM_IS_INTERNED(md)) {
+ char *k = grpc_slice_to_c_string(GRPC_MDKEY(md));
+ char *v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(
+ GPR_DEBUG,
+ "Decode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",
+ k, v, GRPC_MDELEM_IS_INTERNED(md), GRPC_MDELEM_STORAGE(md),
+ grpc_slice_is_interned(GRPC_MDKEY(md)),
+ grpc_slice_is_interned(GRPC_MDVALUE(md)));
+ gpr_free(k);
+ gpr_free(v);
+ }
if (add_to_table) {
+ GPR_ASSERT(GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_INTERNED ||
+ GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC);
grpc_error *err = grpc_chttp2_hptbl_add(exec_ctx, &p->table, md);
if (err != GRPC_ERROR_NONE) return err;
}
@@ -681,10 +699,28 @@ static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
return GRPC_ERROR_NONE;
}
-static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
- grpc_chttp2_hpack_parser_string *str) {
- grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length);
- str->length = 0;
+static grpc_slice take_string(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_hpack_parser *p,
+ grpc_chttp2_hpack_parser_string *str,
+ bool intern) {
+ grpc_slice s;
+ if (!str->copied) {
+ if (intern) {
+ s = grpc_slice_intern(str->data.referenced);
+ grpc_slice_unref_internal(exec_ctx, str->data.referenced);
+ } else {
+ s = str->data.referenced;
+ }
+ str->copied = true;
+ str->data.referenced = grpc_empty_slice();
+ } else if (intern) {
+ s = grpc_slice_intern(grpc_slice_from_static_buffer(
+ str->data.copied.str, str->data.copied.length));
+ } else {
+ s = grpc_slice_from_copied_buffer(str->data.copied.str,
+ str->data.copied.length);
+ }
+ str->data.copied.length = 0;
return s;
}
@@ -771,8 +807,8 @@ static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (md == NULL) {
+ grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ if (GRPC_MDISNULL(md)) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
@@ -813,12 +849,13 @@ static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 1);
+ grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(exec_ctx, p, &p->value, true)),
+ 1);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -828,10 +865,11 @@ static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, take_string(p, &p->key),
- take_string(p, &p->value)),
- 1);
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
+ take_string(exec_ctx, p, &p->value, true)),
+ 1);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -881,12 +919,13 @@ static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0);
+ grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(exec_ctx, p, &p->value, false)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -896,10 +935,11 @@ static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, take_string(p, &p->key),
- take_string(p, &p->value)),
- 0);
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
+ take_string(exec_ctx, p, &p->value, false)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -949,12 +989,13 @@ static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0);
+ grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(exec_ctx, p, &p->value, false)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -964,10 +1005,11 @@ static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
- exec_ctx, take_string(p, &p->key),
- take_string(p, &p->value)),
- 0);
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
+ take_string(exec_ctx, p, &p->value, false)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -1261,14 +1303,15 @@ static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
static void append_bytes(grpc_chttp2_hpack_parser_string *str,
const uint8_t *data, size_t length) {
if (length == 0) return;
- if (length + str->length > str->capacity) {
- GPR_ASSERT(str->length + length <= UINT32_MAX);
- str->capacity = (uint32_t)(str->length + length);
- str->str = gpr_realloc(str->str, str->capacity);
+ if (length + str->data.copied.length > str->data.copied.capacity) {
+ GPR_ASSERT(str->data.copied.length + length <= UINT32_MAX);
+ str->data.copied.capacity = (uint32_t)(str->data.copied.length + length);
+ str->data.copied.str =
+ gpr_realloc(str->data.copied.str, str->data.copied.capacity);
}
- memcpy(str->str + str->length, data, length);
- GPR_ASSERT(length <= UINT32_MAX - str->length);
- str->length += (uint32_t)length;
+ memcpy(str->data.copied.str + str->data.copied.length, data, length);
+ GPR_ASSERT(length <= UINT32_MAX - str->data.copied.length);
+ str->data.copied.length += (uint32_t)length;
}
static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
@@ -1351,11 +1394,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
}
-/* append a null terminator to a string */
static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) {
- uint8_t terminator = 0;
uint8_t decoded[2];
uint32_t bits;
grpc_chttp2_hpack_parser_string *str = p->parsing.str;
@@ -1396,8 +1437,6 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
append_bytes(str, decoded, 2);
break;
}
- append_bytes(str, &terminator, 1);
- p->parsing.str->length--; /* don't actually count the null terminator */
return GRPC_ERROR_NONE;
}
@@ -1472,8 +1511,18 @@ static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx,
const uint8_t *cur, const uint8_t *end,
uint8_t binary,
grpc_chttp2_hpack_parser_string *str) {
+ if (!p->huff && binary == NOT_BINARY && (end - cur) >= (intptr_t)p->strlen &&
+ p->current_slice_refcount != NULL) {
+ str->copied = false;
+ str->data.referenced.refcount = p->current_slice_refcount;
+ str->data.referenced.data.refcounted.bytes = (uint8_t *)cur;
+ str->data.referenced.data.refcounted.length = p->strlen;
+ grpc_slice_ref_internal(str->data.referenced);
+ return parse_next(exec_ctx, p, cur + p->strlen, end);
+ }
p->strgot = 0;
- str->length = 0;
+ str->copied = true;
+ str->data.copied.length = 0;
p->parsing.str = str;
p->huff_state = 0;
p->binary = binary;
@@ -1490,21 +1539,22 @@ static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
/* check if a key represents a binary header or not */
static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
- return grpc_is_binary_header(p->key.str, p->key.length);
+ return grpc_is_binary_header(
+ p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str,
+ p->key.data.copied.length)
+ : p->key.data.referenced);
}
static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
bool *is) {
- grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (!elem) {
+ grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ if (GRPC_MDISNULL(elem)) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
- *is = grpc_is_binary_header(
- (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
- GRPC_SLICE_LENGTH(elem->key->slice));
+ *is = grpc_is_binary_header(GRPC_MDKEY(elem));
return GRPC_ERROR_NONE;
}
@@ -1539,12 +1589,14 @@ void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx,
p->on_header = NULL;
p->on_header_user_data = NULL;
p->state = parse_begin;
- p->key.str = NULL;
- p->key.capacity = 0;
- p->key.length = 0;
- p->value.str = NULL;
- p->value.capacity = 0;
- p->value.length = 0;
+ p->key.data.referenced = grpc_empty_slice();
+ p->key.data.copied.str = NULL;
+ p->key.data.copied.capacity = 0;
+ p->key.data.copied.length = 0;
+ p->value.data.referenced = grpc_empty_slice();
+ p->value.data.copied.str = NULL;
+ p->value.data.copied.capacity = 0;
+ p->value.data.copied.length = 0;
p->dynamic_table_update_allowed = 2;
p->last_error = GRPC_ERROR_NONE;
grpc_chttp2_hptbl_init(exec_ctx, &p->table);
@@ -1559,19 +1611,24 @@ void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p) {
grpc_chttp2_hptbl_destroy(exec_ctx, &p->table);
GRPC_ERROR_UNREF(p->last_error);
- gpr_free(p->key.str);
- gpr_free(p->value.str);
+ grpc_slice_unref_internal(exec_ctx, p->key.data.referenced);
+ grpc_slice_unref_internal(exec_ctx, p->value.data.referenced);
+ gpr_free(p->key.data.copied.str);
+ gpr_free(p->value.data.copied.str);
}
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
- const uint8_t *beg,
- const uint8_t *end) {
+ grpc_slice slice) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple
steps in the event of a large chunk of data to limit
stack space usage when no tail call optimization is
available */
- return p->state(exec_ctx, p, beg, end);
+ p->current_slice_refcount = slice.refcount;
+ grpc_error *error = p->state(exec_ctx, p, GRPC_SLICE_START_PTR(slice),
+ GRPC_SLICE_END_PTR(slice));
+ p->current_slice_refcount = NULL;
+ return error;
}
typedef void (*maybe_complete_func_type)(grpc_exec_ctx *exec_ctx,
@@ -1587,7 +1644,7 @@ static void force_client_rst_stream(grpc_exec_ctx *exec_ctx, void *sp,
grpc_chttp2_transport *t = s->t;
if (!s->write_closed) {
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));
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);
@@ -1605,8 +1662,7 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
if (s != NULL) {
s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
}
- grpc_error *error = grpc_chttp2_hpack_parser_parse(
- exec_ctx, parser, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_END_PTR(slice));
+ grpc_error *error = grpc_chttp2_hpack_parser_parse(exec_ctx, parser, slice);
if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return error;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 52ccf1e7a7..a817183eb5 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -49,14 +49,20 @@ typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
const uint8_t *end);
typedef struct {
- char *str;
- uint32_t length;
- uint32_t capacity;
+ bool copied;
+ struct {
+ grpc_slice referenced;
+ struct {
+ char *str;
+ uint32_t length;
+ uint32_t capacity;
+ } copied;
+ } data;
} grpc_chttp2_hpack_parser_string;
struct grpc_chttp2_hpack_parser {
/* user specified callback for each header output */
- void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem *md);
+ void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem md);
void *on_header_user_data;
grpc_error *last_error;
@@ -67,6 +73,8 @@ struct grpc_chttp2_hpack_parser {
const grpc_chttp2_hpack_parser_state *next_state;
/* what to do after skipping prioritization data */
grpc_chttp2_hpack_parser_state after_prioritization;
+ /* the refcount of the slice that we're currently parsing */
+ grpc_slice_refcount *current_slice_refcount;
/* the value we're currently parsing */
union {
uint32_t *value;
@@ -106,11 +114,9 @@ void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
-/* returns 1 on success, 0 on error */
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
- const uint8_t *beg,
- const uint8_t *end);
+ grpc_slice slice);
/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
the transport */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 26d4036d49..62dd1b8cab 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -190,8 +190,11 @@ void grpc_chttp2_hptbl_init(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
- tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
- exec_ctx, static_table[i].key, static_table[i].value);
+ tbl->static_ents[i - 1] = grpc_mdelem_from_slices(
+ exec_ctx,
+ grpc_slice_intern(grpc_slice_from_static_string(static_table[i].key)),
+ grpc_slice_intern(
+ grpc_slice_from_static_string(static_table[i].value)));
}
}
@@ -208,8 +211,8 @@ void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx,
gpr_free(tbl->ents);
}
-grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
- uint32_t tbl_index) {
+grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+ uint32_t tbl_index) {
/* Static table comes first, just return an entry from it */
if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return tbl->static_ents[tbl_index - 1];
@@ -222,14 +225,14 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
return tbl->ents[offset];
}
/* Invalid entry: return error */
- return NULL;
+ return GRPC_MDNULL;
}
/* Evict one element from the table */
static void evict1(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
- grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
- size_t elem_bytes = GRPC_SLICE_LENGTH(first_ent->key->slice) +
- GRPC_SLICE_LENGTH(first_ent->value->slice) +
+ grpc_mdelem first_ent = tbl->ents[tbl->first_ent];
+ size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(first_ent)) +
+ GRPC_SLICE_LENGTH(GRPC_MDVALUE(first_ent)) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
tbl->mem_used -= (uint32_t)elem_bytes;
@@ -239,7 +242,7 @@ static void evict1(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
}
static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) {
- grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
+ grpc_mdelem *ents = gpr_malloc(sizeof(*ents) * new_cap);
uint32_t i;
for (i = 0; i < tbl->num_ents; i++) {
@@ -301,10 +304,10 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
}
grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+ grpc_chttp2_hptbl *tbl, grpc_mdelem md) {
/* determine how many bytes of buffer this entry represents */
- size_t elem_bytes = GRPC_SLICE_LENGTH(md->key->slice) +
- GRPC_SLICE_LENGTH(md->value->slice) +
+ size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) +
+ GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
@@ -352,16 +355,16 @@ grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
- const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+ const grpc_chttp2_hptbl *tbl, grpc_mdelem md) {
grpc_chttp2_hptbl_find_result r = {0, 0};
uint32_t i;
/* See if the string is in the static table */
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
- grpc_mdelem *ent = tbl->static_ents[i];
- if (md->key != ent->key) continue;
+ grpc_mdelem ent = tbl->static_ents[i];
+ if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue;
r.index = i + 1u;
- r.has_value = md->value == ent->value;
+ r.has_value = grpc_slice_eq(GRPC_MDVALUE(md), GRPC_MDVALUE(ent));
if (r.has_value) return r;
}
@@ -369,10 +372,10 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
for (i = 0; i < tbl->num_ents; i++) {
uint32_t idx =
(uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
- grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
- if (md->key != ent->key) continue;
+ grpc_mdelem ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
+ if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue;
r.index = idx;
- r.has_value = md->value == ent->value;
+ r.has_value = grpc_slice_eq(GRPC_MDVALUE(md), GRPC_MDVALUE(ent));
if (r.has_value) return r;
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 144574ef06..32a0380e00 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -79,8 +79,8 @@ typedef struct {
/* a circular buffer of headers - this is stored in the opposite order to
what hpack specifies, in order to simplify table management a little...
meaning lookups need to SUBTRACT from the end position */
- grpc_mdelem **ents;
- grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
+ grpc_mdelem *ents;
+ grpc_mdelem static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
} grpc_chttp2_hptbl;
/* initialize a hpack table */
@@ -94,12 +94,12 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
uint32_t bytes);
/* lookup a table entry based on its hpack index */
-grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
- uint32_t index);
+grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+ uint32_t index);
/* add a table entry to the index */
grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hptbl *tbl,
- grpc_mdelem *md) GRPC_MUST_USE_RESULT;
+ grpc_mdelem md) GRPC_MUST_USE_RESULT;
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
@@ -107,6 +107,6 @@ typedef struct {
int has_value;
} grpc_chttp2_hptbl_find_result;
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
- const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
+ const grpc_chttp2_hptbl *tbl, grpc_mdelem md);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H */
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.c b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
index 5d1094999c..c91b019aa0 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.c
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
@@ -57,7 +57,7 @@ void grpc_chttp2_incoming_metadata_buffer_destroy(
}
void grpc_chttp2_incoming_metadata_buffer_add(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) {
+ grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem) {
GPR_ASSERT(!buffer->published);
if (buffer->capacity == buffer->count) {
buffer->capacity = GPR_MAX(8, 2 * buffer->capacity);
@@ -68,6 +68,19 @@ void grpc_chttp2_incoming_metadata_buffer_add(
buffer->size += GRPC_MDELEM_LENGTH(elem);
}
+void grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_mdelem elem) {
+ for (size_t i = 0; i < buffer->count; i++) {
+ if (grpc_slice_eq(GRPC_MDKEY(buffer->elems[i].md), GRPC_MDKEY(elem))) {
+ GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
+ buffer->elems[i].md = elem;
+ return;
+ }
+ }
+ grpc_chttp2_incoming_metadata_buffer_add(buffer, elem);
+}
+
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) {
GPR_ASSERT(!buffer->published);
@@ -75,21 +88,20 @@ void grpc_chttp2_incoming_metadata_buffer_set_deadline(
}
void grpc_chttp2_incoming_metadata_buffer_publish(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) {
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_metadata_batch *batch) {
GPR_ASSERT(!buffer->published);
buffer->published = 1;
if (buffer->count > 0) {
size_t i;
- for (i = 1; i < buffer->count; i++) {
- buffer->elems[i].prev = &buffer->elems[i - 1];
- }
- for (i = 0; i < buffer->count - 1; i++) {
- buffer->elems[i].next = &buffer->elems[i + 1];
+ for (i = 0; i < buffer->count; i++) {
+ /* TODO(ctiller): do something better here */
+ if (!GRPC_LOG_IF_ERROR("grpc_chttp2_incoming_metadata_buffer_publish",
+ grpc_metadata_batch_link_tail(
+ exec_ctx, batch, &buffer->elems[i]))) {
+ GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
+ }
}
- buffer->elems[0].prev = NULL;
- buffer->elems[buffer->count - 1].next = NULL;
- batch->list.head = &buffer->elems[0];
- batch->list.tail = &buffer->elems[buffer->count - 1];
} else {
batch->list.head = batch->list.tail = NULL;
}
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index 7a0c4da15f..1eac6fc150 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -51,10 +51,14 @@ void grpc_chttp2_incoming_metadata_buffer_init(
void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer);
void grpc_chttp2_incoming_metadata_buffer_publish(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_metadata_batch *batch);
void grpc_chttp2_incoming_metadata_buffer_add(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem);
+ grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem);
+void grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_mdelem elem);
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline);
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index ea7beb4c2b..1dabf9edba 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -50,7 +50,9 @@
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/pid_controller.h"
#include "src/core/lib/transport/transport_impl.h"
/* streams are kept in various linked lists depending on what things need to
@@ -59,6 +61,7 @@ typedef enum {
GRPC_CHTTP2_LIST_WRITABLE,
GRPC_CHTTP2_LIST_WRITING,
GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
+ GRPC_CHTTP2_LIST_STALLED_BY_STREAM,
/** streams that are waiting to start because there are too many concurrent
streams on the connection */
GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY,
@@ -72,6 +75,34 @@ typedef enum {
GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER,
} grpc_chttp2_write_state;
+typedef enum {
+ GRPC_CHTTP2_PING_ON_NEXT_WRITE = 0,
+ GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE,
+ GRPC_CHTTP2_PING_TYPE_COUNT /* must be last */
+} grpc_chttp2_ping_type;
+
+typedef enum {
+ GRPC_CHTTP2_PCL_INITIATE = 0,
+ GRPC_CHTTP2_PCL_NEXT,
+ GRPC_CHTTP2_PCL_INFLIGHT,
+ GRPC_CHTTP2_PCL_COUNT /* must be last */
+} grpc_chttp2_ping_closure_list;
+
+typedef struct {
+ grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT];
+ uint64_t inflight_id;
+} grpc_chttp2_ping_queue;
+
+typedef struct {
+ gpr_timespec min_time_between_pings;
+ int max_pings_without_data;
+} grpc_chttp2_repeated_ping_policy;
+
+typedef struct {
+ gpr_timespec last_ping_sent_time;
+ int pings_before_data_required;
+} grpc_chttp2_repeated_ping_state;
+
/* deframer state for the overall http2 stream of bytes */
typedef enum {
/* prefix: one entry per http2 connection prefix byte */
@@ -144,14 +175,6 @@ typedef enum {
GRPC_CHTTP2_GOAWAY_SENT,
} grpc_chttp2_sent_goaway_state;
-/* Outstanding ping request data */
-typedef struct grpc_chttp2_outstanding_ping {
- uint8_t id[8];
- grpc_closure *on_recv;
- struct grpc_chttp2_outstanding_ping *next;
- struct grpc_chttp2_outstanding_ping *prev;
-} grpc_chttp2_outstanding_ping;
-
typedef struct grpc_chttp2_write_cb {
int64_t call_at_byte;
grpc_closure *closure;
@@ -271,16 +294,19 @@ struct grpc_chttp2_transport {
copied to next_stream_id in parsing when parsing commences */
uint32_t next_stream_id;
- /** how far to lookahead in a stream? */
- uint32_t stream_lookahead;
-
/** last new stream id */
uint32_t last_new_stream_id;
- /** pings awaiting responses */
- grpc_chttp2_outstanding_ping pings;
- /** next payload for an outgoing ping */
- uint64_t ping_counter;
+ /** ping queues for various ping insertion points */
+ grpc_chttp2_ping_queue ping_queues[GRPC_CHTTP2_PING_TYPE_COUNT];
+ grpc_chttp2_repeated_ping_policy ping_policy;
+ grpc_chttp2_repeated_ping_state ping_state;
+ uint64_t ping_ctr; /* unique id for pings */
+
+ /** ping acks */
+ size_t ping_ack_count;
+ size_t ping_ack_capacity;
+ uint64_t *ping_acks;
/** parser for headers */
grpc_chttp2_hpack_parser hpack_parser;
@@ -324,6 +350,13 @@ struct grpc_chttp2_transport {
grpc_chttp2_write_cb *write_cb_pool;
+ /* bdp estimator */
+ grpc_bdp_estimator bdp_estimator;
+ grpc_pid_controller pid_controller;
+ grpc_closure start_bdp_ping_locked;
+ grpc_closure finish_bdp_ping_locked;
+ gpr_timespec last_pid_update;
+
/* if non-NULL, close the transport with this error when writes are finished
*/
grpc_error *close_transport_on_writes_finished;
@@ -362,12 +395,10 @@ struct grpc_chttp2_stream {
/** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id;
- /** window available for us to send to peer */
- int64_t outgoing_window;
- /** The number of bytes the upper layers have offered to receive.
- As the upper layer offers more bytes, this value increases.
- As bytes are read, this value decreases. */
- uint32_t max_recv_bytes;
+ /** window available for us to send to peer, over or under the initial window
+ * size of the transport... ie:
+ * outgoing_window = outgoing_window_delta + transport.initial_window_size */
+ int64_t outgoing_window_delta;
/** things the upper layers would like to send */
grpc_metadata_batch *send_initial_metadata;
grpc_closure *send_initial_metadata_finished;
@@ -428,8 +459,10 @@ struct grpc_chttp2_stream {
grpc_error *forced_close_error;
/** how many header frames have we received? */
uint8_t header_frames_received;
- /** window available for peer to send to us */
- int64_t incoming_window;
+ /** window available for peer to send to us (as a delta on
+ * transport.initial_window_size)
+ * incoming_window = incoming_window_delta + transport.initial_window_size */
+ int64_t incoming_window_delta;
/** parsing state for data frames */
grpc_chttp2_data_parser data_parser;
/** number of bytes received - reset at end of parse thread execution */
@@ -478,36 +511,43 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
/** Get a writable stream
returns non-zero if there was a stream available */
-int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s);
+bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
bool grpc_chttp2_list_remove_writable_stream(
grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT;
bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
-int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t);
-int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s);
+bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t);
+bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
-int grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s);
+bool grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
-int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s);
+bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
-int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s);
+bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
+void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s);
+bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s);
+bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s);
+
grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t,
uint32_t id);
grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx,
@@ -618,8 +658,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
uint32_t stream_id, int64_t val1, int64_t val2);
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_stream *stream,
- grpc_status_code status, grpc_slice *details);
+ grpc_chttp2_stream *stream, grpc_error *error);
void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, int close_reads,
@@ -673,13 +712,23 @@ void grpc_chttp2_incoming_byte_stream_finished(
grpc_error *error);
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- const uint8_t *opaque_8bytes);
+ uint64_t id);
+
+typedef enum {
+ /* don't initiate a transport write, but piggyback on the next one */
+ GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK,
+ /* initiate a covered write */
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
+ /* initiate an uncovered write */
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED
+} grpc_chttp2_stream_write_type;
/** add a ref to the stream and add it to the writable list;
ref will be dropped in writing.c */
void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, bool covered_by_poller,
+ grpc_chttp2_stream *s,
+ grpc_chttp2_stream_write_type type,
const char *reason);
void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 4fb5dc7bd2..24bd93067b 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -39,10 +39,11 @@
#include <grpc/support/log.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/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/status_conversion.h"
#include "src/core/lib/transport/timeout_encoding.h"
static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
@@ -200,7 +201,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
return err;
}
if (t->incoming_frame_size == 0) {
- err = parse_frame_slice(exec_ctx, t, gpr_empty_slice(), 1);
+ err = parse_frame_slice(exec_ctx, t, grpc_empty_slice(), 1);
if (err != GRPC_ERROR_NONE) {
return err;
}
@@ -335,7 +336,7 @@ static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
return GRPC_ERROR_NONE;
}
-static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) {
+static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem md) {
GRPC_MDELEM_UNREF(exec_ctx, md);
}
@@ -375,25 +376,45 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
return err;
}
+ uint32_t target_incoming_window = GPR_MAX(
+ t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+ 1024);
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window,
incoming_frame_size);
+ if (t->incoming_window <= target_incoming_window / 2) {
+ grpc_chttp2_initiate_write(exec_ctx, t, false, "flow_control");
+ }
if (s != NULL) {
- if (incoming_frame_size > s->incoming_window) {
+ if (incoming_frame_size >
+ s->incoming_window_delta +
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]) {
char *msg;
gpr_asprintf(&msg,
"frame of size %d overflows incoming window of %" PRId64,
- t->incoming_frame_size, s->incoming_window);
+ t->incoming_frame_size,
+ s->incoming_window_delta +
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
}
- GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window,
+ GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window_delta,
incoming_frame_size);
+ if ((int64_t)t->settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] +
+ (int64_t)s->incoming_window_delta - (int64_t)s->announce_window <=
+ (int64_t)t->settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] /
+ 2) {
+ grpc_chttp2_become_writable(exec_ctx, t, s,
+ GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED,
+ "window-update-required");
+ }
s->received_bytes += incoming_frame_size;
- s->max_recv_bytes -=
- (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size);
}
return GRPC_ERROR_NONE;
@@ -432,7 +453,7 @@ error_handler:
}
grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
+ GRPC_HTTP2_PROTOCOL_ERROR,
&s->stats.outgoing));
return init_skip_frame_parser(exec_ctx, t, 0);
} else {
@@ -443,7 +464,7 @@ error_handler:
static void free_timeout(void *p) { gpr_free(p); }
static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
- grpc_mdelem *md) {
+ grpc_mdelem md) {
grpc_chttp2_transport *t = tp;
grpc_chttp2_stream *s = t->incoming_stream;
@@ -451,32 +472,42 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
GPR_ASSERT(s != NULL);
- GRPC_CHTTP2_IF_TRACING(gpr_log(
- GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
- grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
+ if (grpc_http_trace) {
+ char *key = grpc_slice_to_c_string(GRPC_MDKEY(md));
+ char *value =
+ grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id,
+ t->is_client ? "CLI" : "SVR", key, value);
+ gpr_free(key);
+ gpr_free(value);
+ }
- if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
- if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
- if (!cached_timeout) {
+ gpr_timespec timeout;
+ if (cached_timeout == NULL) {
/* not already parsed: parse it now, and store the result away */
cached_timeout = gpr_malloc(sizeof(gpr_timespec));
- if (!grpc_http2_decode_timeout(grpc_mdstr_as_c_string(md->value),
- cached_timeout)) {
- gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
- grpc_mdstr_as_c_string(md->value));
+ if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) {
+ char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+ gpr_free(val);
*cached_timeout = gpr_inf_future(GPR_TIMESPAN);
}
- cached_timeout =
- grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ timeout = *cached_timeout;
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ } else {
+ timeout = *cached_timeout;
}
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&s->metadata_buffer[0],
- gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
+ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout));
GRPC_MDELEM_UNREF(exec_ctx, md);
} else {
const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
@@ -505,7 +536,7 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
}
static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
- grpc_mdelem *md) {
+ grpc_mdelem md) {
grpc_chttp2_transport *t = tp;
grpc_chttp2_stream *s = t->incoming_stream;
@@ -513,11 +544,18 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
GPR_ASSERT(s != NULL);
- GRPC_CHTTP2_IF_TRACING(gpr_log(
- GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
- grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
+ if (grpc_http_trace) {
+ char *key = grpc_slice_to_c_string(GRPC_MDKEY(md));
+ char *value =
+ grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id,
+ t->is_client ? "CLI" : "SVR", key, value);
+ gpr_free(key);
+ gpr_free(value);
+ }
- if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
@@ -733,14 +771,13 @@ static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
if (grpc_http_trace) {
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
- grpc_error_free_string(msg);
}
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
if (s) {
s->forced_close_error = err;
grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
+ GRPC_HTTP2_PROTOCOL_ERROR,
&s->stats.outgoing));
} else {
GRPC_ERROR_UNREF(err);
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c
index a60264cc51..078818fb18 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.c
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.c
@@ -37,14 +37,14 @@
/* core list management */
-static int stream_list_empty(grpc_chttp2_transport *t,
- grpc_chttp2_stream_list_id id) {
+static bool stream_list_empty(grpc_chttp2_transport *t,
+ grpc_chttp2_stream_list_id id) {
return t->lists[id].head == NULL;
}
-static int stream_list_pop(grpc_chttp2_transport *t,
- grpc_chttp2_stream **stream,
- grpc_chttp2_stream_list_id id) {
+static bool stream_list_pop(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **stream,
+ grpc_chttp2_stream_list_id id) {
grpc_chttp2_stream *s = t->lists[id].head;
if (s) {
grpc_chttp2_stream *new_head = s->links[id].next;
@@ -124,8 +124,8 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t,
return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE);
}
-int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s) {
+bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE);
}
@@ -139,12 +139,12 @@ bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t,
return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING);
}
-int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) {
+bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) {
return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING);
}
-int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s) {
+bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING);
}
@@ -153,8 +153,8 @@ void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t,
stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
}
-int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s) {
+bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
}
@@ -168,8 +168,8 @@ void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t,
stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
}
-int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
- grpc_chttp2_stream **s) {
+bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
}
@@ -177,3 +177,18 @@ void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
}
+
+void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s) {
+ stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
+}
+
+bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
+ return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
+}
+
+bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s) {
+ return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
+}
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 84554d327d..05e6f59947 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -37,9 +37,9 @@
#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/slice/slice_internal.h"
+#include "src/core/lib/transport/http2_errors.h"
static void add_to_write_list(grpc_chttp2_write_cb **list,
grpc_chttp2_write_cb *cb) {
@@ -56,6 +56,75 @@ static void finish_write_cb(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->write_cb_pool = cb;
}
+static void collapse_pings_from_into(grpc_chttp2_transport *t,
+ grpc_chttp2_ping_type ping_type,
+ grpc_chttp2_ping_queue *pq) {
+ for (size_t i = 0; i < GRPC_CHTTP2_PCL_COUNT; i++) {
+ grpc_closure_list_move(&t->ping_queues[ping_type].lists[i], &pq->lists[i]);
+ }
+}
+
+static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_ping_type ping_type) {
+ grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type];
+ if (grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) {
+ /* no ping needed: wait */
+ return;
+ }
+ if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) {
+ /* ping already in-flight: wait */
+ if (grpc_http_trace || grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "Ping delayed [%p]: already pinging", t->peer_string);
+ }
+ return;
+ }
+ if (t->ping_state.pings_before_data_required == 0 &&
+ t->ping_policy.max_pings_without_data != 0) {
+ /* need to send something of substance before sending a ping again */
+ if (grpc_http_trace || grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "Ping delayed [%p]: too many recent pings: %d/%d",
+ t->peer_string, t->ping_state.pings_before_data_required,
+ t->ping_policy.max_pings_without_data);
+ }
+ return;
+ }
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ gpr_timespec elapsed = gpr_time_sub(now, t->ping_state.last_ping_sent_time);
+ /*gpr_log(GPR_DEBUG, "elapsed:%d.%09d min:%d.%09d", (int)elapsed.tv_sec,
+ elapsed.tv_nsec, (int)t->ping_policy.min_time_between_pings.tv_sec,
+ (int)t->ping_policy.min_time_between_pings.tv_nsec);*/
+ if (gpr_time_cmp(elapsed, t->ping_policy.min_time_between_pings) < 0) {
+ /* not enough elapsed time between successive pings */
+ if (grpc_http_trace || grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG,
+ "Ping delayed [%p]: not enough time elapsed since last ping",
+ t->peer_string);
+ }
+ return;
+ }
+ /* coalesce equivalent pings into this one */
+ switch (ping_type) {
+ case GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE:
+ collapse_pings_from_into(t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, pq);
+ break;
+ case GRPC_CHTTP2_PING_ON_NEXT_WRITE:
+ break;
+ case GRPC_CHTTP2_PING_TYPE_COUNT:
+ GPR_UNREACHABLE_CODE(break);
+ }
+ pq->inflight_id = t->ping_ctr * GRPC_CHTTP2_PING_TYPE_COUNT + ping_type;
+ t->ping_ctr++;
+ grpc_closure_list_sched(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INITIATE]);
+ grpc_closure_list_move(&pq->lists[GRPC_CHTTP2_PCL_NEXT],
+ &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]);
+ grpc_slice_buffer_add(&t->outbuf,
+ grpc_chttp2_ping_create(false, pq->inflight_id));
+ t->ping_state.last_ping_sent_time = now;
+ t->ping_state.pings_before_data_required -=
+ (t->ping_state.pings_before_data_required != 0);
+}
+
static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, int64_t send_bytes,
grpc_chttp2_write_cb **list, grpc_error *error) {
@@ -139,6 +208,8 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
s->sent_initial_metadata = true;
sent_initial_metadata = true;
now_writing = true;
+ t->ping_state.pings_before_data_required =
+ t->ping_policy.max_pings_without_data;
}
/* send any window updates */
if (s->announce_window > 0) {
@@ -146,15 +217,22 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_add(&t->outbuf,
grpc_chttp2_window_update_create(
s->id, s->announce_window, &s->stats.outgoing));
+ t->ping_state.pings_before_data_required =
+ t->ping_policy.max_pings_without_data;
GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce);
}
if (sent_initial_metadata) {
/* send any body bytes, if allowed by flow control */
if (s->flow_controlled_buffer.length > 0) {
- uint32_t max_outgoing =
- (uint32_t)GPR_MIN(t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
- GPR_MIN(s->outgoing_window, t->outgoing_window));
+ uint32_t stream_outgoing_window = (uint32_t)GPR_MAX(
+ 0,
+ s->outgoing_window_delta +
+ (int64_t)t->settings[GRPC_PEER_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
+ uint32_t max_outgoing = (uint32_t)GPR_MIN(
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
+ GPR_MIN(stream_outgoing_window, t->outgoing_window));
if (max_outgoing > 0) {
uint32_t send_bytes =
(uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length);
@@ -167,16 +245,18 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes,
is_last_frame, &s->stats.outgoing,
&t->outbuf);
- GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window,
+ GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta,
send_bytes);
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window,
send_bytes);
+ t->ping_state.pings_before_data_required =
+ t->ping_policy.max_pings_without_data;
if (is_last_frame) {
s->send_trailing_metadata = NULL;
s->sent_trailing_metadata = true;
if (!t->is_client && !s->read_closed) {
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));
}
}
@@ -189,6 +269,9 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
} else if (t->outgoing_window == 0) {
grpc_chttp2_list_add_stalled_by_transport(t, s);
now_writing = true;
+ } else if (stream_outgoing_window == 0) {
+ grpc_chttp2_list_add_stalled_by_stream(t, s);
+ now_writing = true;
}
}
if (s->send_trailing_metadata != NULL &&
@@ -209,7 +292,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
if (!t->is_client && !s->read_closed) {
grpc_slice_buffer_add(
&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;
}
@@ -227,15 +310,32 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
/* if the grpc_chttp2_transport is ready to send a window update, do so here
also; 3/4 is a magic number that will likely get tuned soon */
- if (t->announce_incoming_window > 0) {
- uint32_t announced =
- (uint32_t)GPR_MIN(t->announce_incoming_window, UINT32_MAX);
- GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window,
- announced);
+ uint32_t target_incoming_window = GPR_MAX(
+ t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+ 1024);
+ uint32_t threshold_to_send_transport_window_update =
+ t->outbuf.count > 0 ? 3 * target_incoming_window / 4
+ : target_incoming_window / 2;
+ if (t->incoming_window <= threshold_to_send_transport_window_update) {
+ maybe_initiate_ping(exec_ctx, t,
+ GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE);
+ uint32_t announced = (uint32_t)GPR_CLAMP(
+ target_incoming_window - t->incoming_window, 0, UINT32_MAX);
+ GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("write", t, incoming_window, announced);
grpc_transport_one_way_stats throwaway_stats;
grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create(
0, announced, &throwaway_stats));
+ t->ping_state.pings_before_data_required =
+ t->ping_policy.max_pings_without_data;
+ }
+
+ for (size_t i = 0; i < t->ping_ack_count; i++) {
+ grpc_slice_buffer_add(&t->outbuf,
+ grpc_chttp2_ping_create(1, t->ping_acks[i]));
}
+ t->ping_ack_count = 0;
+
+ maybe_initiate_ping(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE);
GPR_TIMER_END("grpc_chttp2_begin_write", 0);
diff --git a/src/core/ext/transport/cronet/transport/cronet_api_dummy.c b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c
index 74327a4214..da6c0b4fbc 100644
--- a/src/core/ext/transport/cronet/transport/cronet_api_dummy.c
+++ b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c
@@ -38,7 +38,7 @@ library, so we can build it in all environments */
#include <grpc/support/log.h>
-#include "third_party/Cronet/bidirectional_stream_c.h"
+#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
#ifdef GRPC_COMPILE_WITH_CRONET
/* link with the real CRONET library in the build system */
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 6f5816390a..d755b1f147 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -44,12 +44,14 @@
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
-#include "third_party/Cronet/bidirectional_stream_c.h"
+#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
#define GRPC_HEADER_SIZE_IN_BYTES 5
@@ -437,9 +439,11 @@ static void on_response_headers_received(
for (size_t i = 0; i < headers->count; i++) {
grpc_chttp2_incoming_metadata_buffer_add(
&s->state.rs.initial_metadata,
- grpc_mdelem_from_metadata_strings(
- &exec_ctx, grpc_mdstr_from_string(headers->headers[i].key),
- grpc_mdstr_from_string(headers->headers[i].value)));
+ grpc_mdelem_from_slices(
+ &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
+ headers->headers[i].key)),
+ grpc_slice_intern(
+ grpc_slice_from_static_string(headers->headers[i].value))));
}
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
@@ -534,9 +538,11 @@ static void on_response_trailers_received(
trailers->headers[i].value);
grpc_chttp2_incoming_metadata_buffer_add(
&s->state.rs.trailing_metadata,
- grpc_mdelem_from_metadata_strings(
- &exec_ctx, grpc_mdstr_from_string(trailers->headers[i].key),
- grpc_mdstr_from_string(trailers->headers[i].value)));
+ grpc_mdelem_from_slices(
+ &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
+ trailers->headers[i].key)),
+ grpc_slice_intern(
+ grpc_slice_from_static_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")) {
@@ -616,27 +622,33 @@ static void convert_metadata_to_cronet_headers(
curr = head;
size_t num_headers = 0;
while (num_headers < num_headers_available) {
- grpc_mdelem *mdelem = curr->md;
+ grpc_mdelem mdelem = curr->md;
curr = curr->next;
- const char *key = grpc_mdstr_as_c_string(mdelem->key);
- const char *value = grpc_mdstr_as_c_string(mdelem->value);
- if (mdelem->key == GRPC_MDSTR_SCHEME ||
- mdelem->key == GRPC_MDSTR_AUTHORITY) {
+ char *key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
+ char *value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
+ if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) ||
+ grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_AUTHORITY)) {
/* Cronet populates these fields on its own */
+ gpr_free(key);
+ gpr_free(value);
continue;
}
- if (mdelem->key == GRPC_MDSTR_METHOD) {
- if (mdelem->value == GRPC_MDSTR_PUT) {
+ if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_METHOD)) {
+ if (grpc_slice_eq(GRPC_MDVALUE(mdelem), GRPC_MDSTR_PUT)) {
*method = "PUT";
} else {
/* POST method in default*/
*method = "POST";
}
+ gpr_free(key);
+ gpr_free(value);
continue;
}
- if (mdelem->key == GRPC_MDSTR_PATH) {
+ if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_PATH)) {
/* Create URL by appending :path value to the hostname */
gpr_asprintf(pp_url, "https://%s%s", host, value);
+ gpr_free(key);
+ gpr_free(value);
continue;
}
CRONET_LOG(GPR_DEBUG, "header %s = %s", key, value);
@@ -662,7 +674,7 @@ static int parse_grpc_header(const uint8_t *data) {
static bool header_has_authority(grpc_linked_mdelem *head) {
while (head != NULL) {
- if (head->md->key == GRPC_MDSTR_AUTHORITY) {
+ if (grpc_slice_eq(GRPC_MDKEY(head->md), GRPC_MDSTR_AUTHORITY)) {
return true;
}
head = head->next;
@@ -843,6 +855,12 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
s->header_array.capacity = s->header_array.count;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_start(%p, %s)", s->cbs, url);
bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array, false);
+ unsigned int header_index;
+ for (header_index = 0; header_index < s->header_array.count;
+ header_index++) {
+ gpr_free((void *)s->header_array.headers[header_index].key);
+ gpr_free((void *)s->header_array.headers[header_index].value);
+ }
stream_state->state_op_done[OP_SEND_INITIAL_METADATA] = true;
result = ACTION_TAKEN_WITH_CALLBACK;
} else if (stream_op->recv_initial_metadata &&
@@ -857,7 +875,8 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_NONE);
} else {
grpc_chttp2_incoming_metadata_buffer_publish(
- &oas->s->state.rs.initial_metadata, stream_op->recv_initial_metadata);
+ exec_ctx, &oas->s->state.rs.initial_metadata,
+ stream_op->recv_initial_metadata);
grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
GRPC_ERROR_NONE);
}
@@ -1013,7 +1032,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
CRONET_LOG(GPR_DEBUG, "running: %p OP_RECV_TRAILING_METADATA", oas);
if (oas->s->state.rs.trailing_metadata_valid) {
grpc_chttp2_incoming_metadata_buffer_publish(
- &oas->s->state.rs.trailing_metadata,
+ exec_ctx, &oas->s->state.rs.trailing_metadata,
stream_op->recv_trailing_metadata);
stream_state->rs.trailing_metadata_valid = false;
}
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 8f08b427fb..ec973d4e7f 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -170,7 +170,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline,
+ grpc_slice path, gpr_timespec start_time, gpr_timespec deadline,
grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
grpc_call_element_args args;
@@ -288,41 +288,10 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
sizeof(grpc_call_stack)));
}
-static void destroy_op(grpc_exec_ctx *exec_ctx, void *op, grpc_error *error) {
- gpr_free(op);
-}
-
-void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
- grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
- memset(op, 0, sizeof(*op));
- op->cancel_error = GRPC_ERROR_CANCELLED;
- op->on_complete =
- grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
-}
-
-void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_status_code status,
- grpc_slice *optional_message) {
- grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
- memset(op, 0, sizeof(*op));
- op->on_complete =
- grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
- grpc_transport_stream_op_add_cancellation_with_message(exec_ctx, op, status,
- optional_message);
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
-}
-
-void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_status_code status,
- grpc_slice *optional_message) {
- grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
- memset(op, 0, sizeof(*op));
- op->on_complete =
- grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
- grpc_transport_stream_op_add_close(exec_ctx, op, status, optional_message);
+void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_error *error) {
+ grpc_transport_stream_op *op = grpc_make_transport_stream_op(NULL);
+ op->cancel_error = error;
elem->filter->start_transport_stream_op(exec_ctx, elem, op);
}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index d9d3a85233..1cf07d43c2 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -81,7 +81,7 @@ typedef struct {
grpc_call_stack *call_stack;
const void *server_transport_data;
grpc_call_context_element *context;
- grpc_mdstr *path;
+ grpc_slice path;
gpr_timespec start_time;
gpr_timespec deadline;
} grpc_call_element_args;
@@ -238,7 +238,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline,
+ grpc_slice path, gpr_timespec start_time, gpr_timespec deadline,
grpc_call_stack *call_stack);
/* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */
@@ -299,18 +299,9 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
grpc_call_element *elem, grpc_transport_stream_op *op);
-void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
- grpc_call_element *cur_elem);
-
-void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
- grpc_call_element *cur_elem,
- grpc_status_code status,
- grpc_slice *optional_message);
-
-void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx,
- grpc_call_element *cur_elem,
- grpc_status_code status,
- grpc_slice *optional_message);
+void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *cur_elem,
+ grpc_error *error);
extern int grpc_trace_channel;
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 337c194b79..c860d60d88 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -45,6 +45,7 @@
#include "src/core/lib/compression/message_compress.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -80,39 +81,6 @@ typedef struct channel_data {
uint32_t supported_compression_algorithms;
} channel_data;
-/** For each \a md element from the incoming metadata, filter out the entry for
- * "grpc-encoding", using its value to populate the call data's
- * compression_algorithm field. */
-static grpc_mdelem *compression_md_filter(grpc_exec_ctx *exec_ctx,
- void *user_data, grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) {
- const char *md_c_str = grpc_mdstr_as_c_string(md->value);
- if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
- &calld->compression_algorithm)) {
- gpr_log(GPR_ERROR,
- "Invalid compression algorithm: '%s' (unknown). Ignoring.",
- md_c_str);
- calld->compression_algorithm = GRPC_COMPRESS_NONE;
- }
- if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
- calld->compression_algorithm)) {
- gpr_log(GPR_ERROR,
- "Invalid compression algorithm: '%s' (previously disabled). "
- "Ignoring.",
- md_c_str);
- calld->compression_algorithm = GRPC_COMPRESS_NONE;
- }
- calld->has_compression_algorithm = 1;
- return NULL;
- }
-
- return md;
-}
-
static int skip_compression(grpc_call_element *elem, uint32_t flags) {
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@@ -131,32 +99,65 @@ static int skip_compression(grpc_call_element *elem, uint32_t flags) {
}
/** Filter initial metadata */
-static void process_send_initial_metadata(
+static grpc_error *process_send_initial_metadata(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_metadata_batch *initial_metadata) GRPC_MUST_USE_RESULT;
+static grpc_error *process_send_initial_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_metadata_batch *initial_metadata) {
+ grpc_error *error;
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
/* Parse incoming request for compression. If any, it'll be available
* at calld->compression_algorithm */
- grpc_metadata_batch_filter(exec_ctx, initial_metadata, compression_md_filter,
- elem);
- if (!calld->has_compression_algorithm) {
+ if (initial_metadata->idx.named.grpc_internal_encoding_request != NULL) {
+ grpc_mdelem md =
+ initial_metadata->idx.named.grpc_internal_encoding_request->md;
+ if (!grpc_compression_algorithm_parse(GRPC_MDVALUE(md),
+ &calld->compression_algorithm)) {
+ char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR,
+ "Invalid compression algorithm: '%s' (unknown). Ignoring.", val);
+ gpr_free(val);
+ calld->compression_algorithm = GRPC_COMPRESS_NONE;
+ }
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
+ calld->compression_algorithm)) {
+ char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR,
+ "Invalid compression algorithm: '%s' (previously disabled). "
+ "Ignoring.",
+ val);
+ gpr_free(val);
+ calld->compression_algorithm = GRPC_COMPRESS_NONE;
+ }
+ calld->has_compression_algorithm = 1;
+
+ grpc_metadata_batch_remove(
+ exec_ctx, initial_metadata,
+ initial_metadata->idx.named.grpc_internal_encoding_request);
+ } else {
/* If no algorithm was found in the metadata and we aren't
* exceptionally skipping compression, fall back to the channel
* default */
calld->compression_algorithm = channeld->default_compression_algorithm;
calld->has_compression_algorithm = 1; /* GPR_TRUE */
}
+
/* hint compression algorithm */
- grpc_metadata_batch_add_tail(
- initial_metadata, &calld->compression_algorithm_storage,
+ error = grpc_metadata_batch_add_tail(
+ exec_ctx, initial_metadata, &calld->compression_algorithm_storage,
grpc_compression_encoding_mdelem(calld->compression_algorithm));
+ if (error != GRPC_ERROR_NONE) return error;
+
/* convey supported compression algorithms */
- grpc_metadata_batch_add_tail(initial_metadata,
- &calld->accept_encoding_storage,
- GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
- channeld->supported_compression_algorithms));
+ error = grpc_metadata_batch_add_tail(
+ exec_ctx, initial_metadata, &calld->accept_encoding_storage,
+ GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
+ channeld->supported_compression_algorithms));
+
+ return error;
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
@@ -247,7 +248,12 @@ static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
if (op->send_initial_metadata) {
- process_send_initial_metadata(exec_ctx, elem, op->send_initial_metadata);
+ grpc_error *error = process_send_initial_metadata(
+ exec_ctx, elem, op->send_initial_metadata);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ return;
+ }
}
if (op->send_message != NULL &&
!skip_compression(elem, op->send_message->flags)) {
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index ccc0619e1c..068c61c92a 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -140,7 +140,7 @@ static void con_get_channel_info(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
const grpc_channel_info *channel_info) {}
-static const grpc_channel_filter connected_channel_filter = {
+const grpc_channel_filter grpc_connected_filter = {
con_start_transport_stream_op,
con_start_transport_op,
sizeof(call_data),
@@ -158,7 +158,7 @@ static const grpc_channel_filter connected_channel_filter = {
static void bind_transport(grpc_channel_stack *channel_stack,
grpc_channel_element *elem, void *t) {
channel_data *cd = (channel_data *)elem->channel_data;
- GPR_ASSERT(elem->filter == &connected_channel_filter);
+ GPR_ASSERT(elem->filter == &grpc_connected_filter);
GPR_ASSERT(cd->transport == NULL);
cd->transport = t;
@@ -178,7 +178,7 @@ bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx,
grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
GPR_ASSERT(t != NULL);
return grpc_channel_stack_builder_append_filter(
- builder, &connected_channel_filter, bind_transport, t);
+ builder, &grpc_connected_filter, bind_transport, t);
}
grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) {
diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h
index 3585c0ecbc..5c7ea9ed26 100644
--- a/src/core/lib/channel/connected_channel.h
+++ b/src/core/lib/channel/connected_channel.h
@@ -36,8 +36,13 @@
#include "src/core/lib/channel/channel_stack_builder.h"
+extern const grpc_channel_filter grpc_connected_filter;
+
bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx,
grpc_channel_stack_builder *builder,
void *arg_must_be_null);
+/* Debug helper to dig the transport stream out of a call element */
+grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem);
+
#endif /* GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index a45a4d4b82..bc9a2effc2 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -56,10 +56,11 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg,
deadline_state->timer_pending = false;
gpr_mu_unlock(&deadline_state->timer_mu);
if (error != GRPC_ERROR_CANCELLED) {
- grpc_slice msg = grpc_slice_from_static_string("Deadline Exceeded");
- grpc_call_element_send_cancel_with_message(
- exec_ctx, elem, GRPC_STATUS_DEADLINE_EXCEEDED, &msg);
- grpc_slice_unref_internal(exec_ctx, msg);
+ grpc_call_element_signal_error(
+ exec_ctx, elem,
+ grpc_error_set_int(GRPC_ERROR_CREATE("Deadline Exceeded"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_DEADLINE_EXCEEDED));
}
GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer");
}
@@ -196,8 +197,7 @@ void grpc_deadline_state_client_start_transport_stream_op(
grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
grpc_transport_stream_op* op) {
grpc_deadline_state* deadline_state = elem->call_data;
- if (op->cancel_error != GRPC_ERROR_NONE ||
- op->close_error != GRPC_ERROR_NONE) {
+ if (op->cancel_error != GRPC_ERROR_NONE) {
cancel_timer_if_needed(exec_ctx, deadline_state);
} else {
// Make sure we know when the call is complete, so that we can cancel
@@ -285,8 +285,7 @@ static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
grpc_transport_stream_op* op) {
server_call_data* calld = elem->call_data;
- if (op->cancel_error != GRPC_ERROR_NONE ||
- op->close_error != GRPC_ERROR_NONE) {
+ if (op->cancel_error != GRPC_ERROR_NONE) {
cancel_timer_if_needed(exec_ctx, &calld->base.deadline_state);
} else {
// If we're receiving initial metadata, we need to get the deadline
diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c
index c052ca5385..5bed2d041d 100644
--- a/src/core/lib/channel/handshaker.c
+++ b/src/core/lib/channel/handshaker.c
@@ -55,8 +55,8 @@ void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
}
void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker) {
- handshaker->vtable->shutdown(exec_ctx, handshaker);
+ grpc_handshaker* handshaker, grpc_error* why) {
+ handshaker->vtable->shutdown(exec_ctx, handshaker, why);
}
void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
@@ -141,14 +141,17 @@ void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
}
void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshake_manager* mgr) {
+ grpc_handshake_manager* mgr,
+ grpc_error* why) {
gpr_mu_lock(&mgr->mu);
// Shutdown the handshaker that's currently in progress, if any.
if (!mgr->shutdown && mgr->index > 0) {
mgr->shutdown = true;
- grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1]);
+ grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1],
+ GRPC_ERROR_REF(why));
}
gpr_mu_unlock(&mgr->mu);
+ GRPC_ERROR_UNREF(why);
}
// Helper function to call either the next handshaker or the
@@ -197,7 +200,8 @@ static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg,
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
grpc_handshake_manager* mgr = arg;
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
- grpc_handshake_manager_shutdown(exec_ctx, mgr);
+ grpc_handshake_manager_shutdown(exec_ctx, mgr,
+ GRPC_ERROR_CREATE("Handshake timed out"));
}
grpc_handshake_manager_unref(exec_ctx, mgr);
}
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index 450b7adaee..a8e3692add 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -86,7 +86,8 @@ typedef struct {
/// Shuts down the handshaker (e.g., to clean up when the operation is
/// aborted in the middle).
- void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
+ void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker,
+ grpc_error* why);
/// Performs handshaking, modifying \a args as needed (e.g., to
/// replace \a endpoint with a wrapped endpoint).
@@ -111,7 +112,7 @@ void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker);
void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker);
+ grpc_handshaker* handshaker, grpc_error* why);
void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker,
grpc_tcp_server_acceptor* acceptor,
@@ -141,7 +142,8 @@ void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
/// The caller must still call grpc_handshake_manager_destroy() after
/// calling this function.
void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshake_manager* mgr);
+ grpc_handshake_manager* mgr,
+ grpc_error* why);
/// Invokes handshakers in the order they were added.
/// Takes ownership of \a endpoint, and then passes that ownership to
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index d154450988..49a2a980e0 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -38,6 +38,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
@@ -88,77 +89,104 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
- grpc_mdelem *static_scheme;
- grpc_mdelem *user_agent;
+ grpc_mdelem static_scheme;
+ grpc_mdelem user_agent;
size_t max_payload_size_for_get;
} channel_data;
-static grpc_mdelem *client_recv_filter(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
- if (md == GRPC_MDELEM_STATUS_200) {
- return NULL;
- } else if (md->key == GRPC_MDSTR_STATUS) {
- char *message_string;
- gpr_asprintf(&message_string, "Received http2 header with status: %s",
- grpc_mdstr_as_c_string(md->value));
- grpc_slice message = grpc_slice_from_copied_string(message_string);
- gpr_free(message_string);
- grpc_call_element_send_close_with_message(exec_ctx, elem,
- GRPC_STATUS_CANCELLED, &message);
- return NULL;
- } else if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
- grpc_slice pct_decoded_msg =
- grpc_permissive_percent_decode_slice(md->value->slice);
- if (grpc_slice_is_equivalent(pct_decoded_msg, md->value->slice)) {
- grpc_slice_unref_internal(exec_ctx, pct_decoded_msg);
- return md;
+static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_metadata_batch *b) {
+ if (b->idx.named.status != NULL) {
+ if (grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) {
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.status);
} else {
- return grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_mdstr_from_slice(exec_ctx, pct_decoded_msg));
+ char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md),
+ GPR_DUMP_ASCII);
+ char *msg;
+ gpr_asprintf(&msg, "Received http2 header with status: %s", val);
+ grpc_error *e = grpc_error_set_str(
+ grpc_error_set_int(
+ grpc_error_set_str(
+ GRPC_ERROR_CREATE(
+ "Received http2 :status header with non-200 OK status"),
+ GRPC_ERROR_STR_VALUE, val),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED),
+ GRPC_ERROR_STR_GRPC_MESSAGE, msg);
+ gpr_free(val);
+ gpr_free(msg);
+ return e;
}
- } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
- return NULL;
- } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
- const char *value_str = grpc_mdstr_as_c_string(md->value);
- if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
- EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
- (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
- value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
- /* Although the C implementation doesn't (currently) generate them,
- any custom +-suffix is explicitly valid. */
- /* TODO(klempner): We should consider preallocating common values such
- as +proto or +json, or at least stashing them if we see them. */
- /* TODO(klempner): Should we be surfacing this to application code? */
+ }
+
+ if (b->idx.named.grpc_message != NULL) {
+ grpc_slice pct_decoded_msg = grpc_permissive_percent_decode_slice(
+ GRPC_MDVALUE(b->idx.named.grpc_message->md));
+ if (grpc_slice_is_equivalent(pct_decoded_msg,
+ GRPC_MDVALUE(b->idx.named.grpc_message->md))) {
+ grpc_slice_unref_internal(exec_ctx, pct_decoded_msg);
} else {
- /* TODO(klempner): We're currently allowing this, but we shouldn't
- see it without a proxy so log for now. */
- gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str);
+ grpc_metadata_batch_set_value(exec_ctx, b->idx.named.grpc_message,
+ pct_decoded_msg);
}
- return NULL;
}
- return md;
+
+ if (b->idx.named.content_type != NULL) {
+ if (!grpc_mdelem_eq(b->idx.named.content_type->md,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
+ if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md),
+ EXPECTED_CONTENT_TYPE,
+ EXPECTED_CONTENT_TYPE_LENGTH) &&
+ (GRPC_SLICE_START_PTR(GRPC_MDVALUE(
+ b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] ==
+ '+' ||
+ GRPC_SLICE_START_PTR(GRPC_MDVALUE(
+ b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] ==
+ ';')) {
+ /* Although the C implementation doesn't (currently) generate them,
+ any custom +-suffix is explicitly valid. */
+ /* TODO(klempner): We should consider preallocating common values such
+ as +proto or +json, or at least stashing them if we see them. */
+ /* TODO(klempner): Should we be surfacing this to application code? */
+ } else {
+ /* TODO(klempner): We're currently allowing this, but we shouldn't
+ see it without a proxy so log for now. */
+ char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.content_type->md),
+ GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "Unexpected content-type '%s'", val);
+ gpr_free(val);
+ }
+ }
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.content_type);
+ }
+
+ return GRPC_ERROR_NONE;
}
static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
void *user_data, grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
- client_recv_filter, elem);
- grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata,
- GRPC_ERROR_REF(error));
+ if (error == GRPC_ERROR_NONE) {
+ error = client_filter_incoming_metadata(exec_ctx, elem,
+ calld->recv_initial_metadata);
+ } else {
+ GRPC_ERROR_REF(error);
+ }
+ grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error);
}
static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
void *user_data, grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- grpc_metadata_batch_filter(exec_ctx, calld->recv_trailing_metadata,
- client_recv_filter, elem);
- grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata,
- GRPC_ERROR_REF(error));
+ if (error == GRPC_ERROR_NONE) {
+ error = client_filter_incoming_metadata(exec_ctx, elem,
+ calld->recv_trailing_metadata);
+ } else {
+ GRPC_ERROR_REF(error);
+ }
+ grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata, error);
}
static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -179,15 +207,12 @@ static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
}
-static grpc_mdelem *client_strip_filter(grpc_exec_ctx *exec_ctx,
- void *user_data, grpc_mdelem *md) {
- /* eat the things we'd like to set ourselves */
- if (md->key == GRPC_MDSTR_METHOD) return NULL;
- if (md->key == GRPC_MDSTR_SCHEME) return NULL;
- if (md->key == GRPC_MDSTR_TE) return NULL;
- if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
- if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
- return md;
+static void remove_if_present(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_metadata_batch_callouts_index idx) {
+ if (batch->idx.array[idx] != NULL) {
+ grpc_metadata_batch_remove(exec_ctx, batch, batch->idx.array[idx]);
+ }
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
@@ -226,18 +251,20 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
}
}
-static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+static grpc_error *hc_mutate_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 *channeld = elem->channel_data;
+ grpc_error *error;
if (op->send_initial_metadata != NULL) {
/* Decide which HTTP VERB to use. We use GET if the request is marked
cacheable, and the operation contains both initial metadata and send
message, and the payload is below the size threshold, and all the data
for this request is immediately available. */
- grpc_mdelem *method = GRPC_MDELEM_METHOD_POST;
+ grpc_mdelem method = GRPC_MDELEM_METHOD_POST;
if ((op->send_initial_metadata_flags &
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
op->send_message != NULL &&
@@ -254,7 +281,7 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Attempt to read the data from send_message and create a header field. */
- if (method == GRPC_MDELEM_METHOD_GET) {
+ if (grpc_mdelem_eq(method, GRPC_MDELEM_METHOD_GET)) {
/* allocate memory to hold the entire payload */
calld->payload_bytes = gpr_malloc(op->send_message->length);
@@ -267,12 +294,14 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
if (calld->send_message_blocked == false) {
/* when all the send_message data is available, then create a MDELEM and
append to headers */
- grpc_mdelem *payload_bin = grpc_mdelem_from_metadata_strings(
+ grpc_mdelem payload_bin = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_GRPC_PAYLOAD_BIN,
- grpc_mdstr_from_buffer(calld->payload_bytes,
- op->send_message->length));
- grpc_metadata_batch_add_tail(op->send_initial_metadata,
- &calld->payload_bin, payload_bin);
+ grpc_slice_from_copied_buffer((const char *)calld->payload_bytes,
+ op->send_message->length));
+ error =
+ grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
+ &calld->payload_bin, payload_bin);
+ if (error != GRPC_ERROR_NONE) return error;
calld->on_complete = op->on_complete;
op->on_complete = &calld->hc_on_complete;
op->send_message = NULL;
@@ -285,21 +314,35 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
}
- grpc_metadata_batch_filter(exec_ctx, op->send_initial_metadata,
- client_strip_filter, elem);
+ remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_METHOD);
+ remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_SCHEME);
+ remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_TE);
+ remove_if_present(exec_ctx, op->send_initial_metadata,
+ GRPC_BATCH_CONTENT_TYPE);
+ remove_if_present(exec_ctx, op->send_initial_metadata,
+ GRPC_BATCH_USER_AGENT);
+
/* Send : prefixed headers, which have to be before any application
layer headers. */
- grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
- method);
- grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
- channeld->static_scheme);
- grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
- GRPC_MDELEM_TE_TRAILERS);
- grpc_metadata_batch_add_tail(
- op->send_initial_metadata, &calld->content_type,
+ error = grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
+ &calld->method, method);
+ if (error != GRPC_ERROR_NONE) return error;
+ error =
+ grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
+ &calld->scheme, channeld->static_scheme);
+ if (error != GRPC_ERROR_NONE) return error;
+ error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
+ &calld->te_trailers,
+ GRPC_MDELEM_TE_TRAILERS);
+ if (error != GRPC_ERROR_NONE) return error;
+ error = grpc_metadata_batch_add_tail(
+ exec_ctx, op->send_initial_metadata, &calld->content_type,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
- grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
- GRPC_MDELEM_REF(channeld->user_agent));
+ if (error != GRPC_ERROR_NONE) return error;
+ error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
+ &calld->user_agent,
+ GRPC_MDELEM_REF(channeld->user_agent));
+ if (error != GRPC_ERROR_NONE) return error;
}
if (op->recv_initial_metadata != NULL) {
@@ -315,6 +358,8 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
calld->on_done_recv_trailing_metadata = op->on_complete;
op->on_complete = &calld->hc_on_recv_trailing_metadata;
}
+
+ return GRPC_ERROR_NONE;
}
static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -322,15 +367,20 @@ static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op) {
GPR_TIMER_BEGIN("hc_start_transport_op", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- hc_mutate_op(exec_ctx, elem, op);
- GPR_TIMER_END("hc_start_transport_op", 0);
- call_data *calld = elem->call_data;
- if (op->send_message != NULL && calld->send_message_blocked) {
- /* Don't forward the op. send_message contains slices that aren't ready
- yet. The call will be forwarded by the op_complete of slice read call. */
+ grpc_error *error = hc_mutate_op(exec_ctx, elem, op);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
} else {
- grpc_call_next_op(exec_ctx, elem, op);
+ call_data *calld = elem->call_data;
+ if (op->send_message != NULL && calld->send_message_blocked) {
+ /* Don't forward the op. send_message contains slices that aren't ready
+ yet. The call will be forwarded by the op_complete of slice read call.
+ */
+ } else {
+ grpc_call_next_op(exec_ctx, elem, op);
+ }
}
+ GPR_TIMER_END("hc_start_transport_op", 0);
}
/* Constructor for call_data */
@@ -367,18 +417,18 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
}
-static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
+static grpc_mdelem scheme_from_args(const grpc_channel_args *args) {
unsigned i;
size_t j;
- grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
- GRPC_MDELEM_SCHEME_HTTPS};
+ grpc_mdelem valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
+ GRPC_MDELEM_SCHEME_HTTPS};
if (args != NULL) {
for (i = 0; i < args->num_args; ++i) {
if (args->args[i].type == GRPC_ARG_STRING &&
strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
- if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
- args->args[i].value.string)) {
+ if (0 == grpc_slice_str_cmp(GRPC_MDVALUE(valid_schemes[j]),
+ args->args[i].value.string)) {
return valid_schemes[j];
}
}
@@ -404,13 +454,13 @@ static size_t max_payload_size_from_args(const grpc_channel_args *args) {
return kMaxPayloadSizeForGet;
}
-static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
- const char *transport_name) {
+static grpc_slice user_agent_from_args(const grpc_channel_args *args,
+ const char *transport_name) {
gpr_strvec v;
size_t i;
int is_first = 1;
char *tmp;
- grpc_mdstr *result;
+ grpc_slice result;
gpr_strvec_init(&v);
@@ -448,7 +498,7 @@ static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
tmp = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v);
- result = grpc_mdstr_from_string(tmp);
+ result = grpc_slice_intern(grpc_slice_from_static_string(tmp));
gpr_free(tmp);
return result;
@@ -464,7 +514,7 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
chand->static_scheme = scheme_from_args(args->channel_args);
chand->max_payload_size_for_get =
max_payload_size_from_args(args->channel_args);
- chand->user_agent = grpc_mdelem_from_metadata_strings(
+ chand->user_agent = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_USER_AGENT,
user_agent_from_args(args->channel_args,
args->optional_transport->vtable->name));
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index f508231238..3f992977c0 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -39,6 +39,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
#define EXPECTED_CONTENT_TYPE "application/grpc"
@@ -47,18 +48,13 @@
extern int grpc_http_trace;
typedef struct call_data {
- uint8_t seen_path;
- uint8_t seen_method;
- uint8_t sent_status;
- uint8_t seen_scheme;
- uint8_t seen_te_trailers;
- uint8_t seen_authority;
- uint8_t seen_payload_bin;
grpc_linked_mdelem status;
grpc_linked_mdelem content_type;
+ /* did this request come with payload-bin */
+ bool seen_payload_bin;
/* flag to ensure payload_bin is delivered only once */
- uint8_t payload_bin_delivered;
+ bool payload_bin_delivered;
grpc_metadata_batch *recv_initial_metadata;
bool *recv_idempotent_request;
@@ -83,109 +79,152 @@ typedef struct call_data {
typedef struct channel_data { uint8_t unused; } channel_data;
-static grpc_mdelem *server_filter_outgoing_metadata(grpc_exec_ctx *exec_ctx,
- void *user_data,
- grpc_mdelem *md) {
- if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
+static grpc_error *server_filter_outgoing_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_metadata_batch *b) {
+ if (b->idx.named.grpc_message != NULL) {
grpc_slice pct_encoded_msg = grpc_percent_encode_slice(
- md->value->slice, grpc_compatible_percent_encoding_unreserved_bytes);
- if (grpc_slice_is_equivalent(pct_encoded_msg, md->value->slice)) {
+ GRPC_MDVALUE(b->idx.named.grpc_message->md),
+ grpc_compatible_percent_encoding_unreserved_bytes);
+ if (grpc_slice_is_equivalent(pct_encoded_msg,
+ GRPC_MDVALUE(b->idx.named.grpc_message->md))) {
grpc_slice_unref_internal(exec_ctx, pct_encoded_msg);
- return md;
} else {
- return grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_mdstr_from_slice(exec_ctx, pct_encoded_msg));
+ grpc_metadata_batch_set_value(exec_ctx, b->idx.named.grpc_message,
+ pct_encoded_msg);
}
- } else {
- return md;
}
+ return GRPC_ERROR_NONE;
}
-static grpc_mdelem *server_filter(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
+static void add_error(const char *error_name, grpc_error **cumulative,
+ grpc_error *new) {
+ if (new == GRPC_ERROR_NONE) return;
+ if (*cumulative == GRPC_ERROR_NONE) {
+ *cumulative = GRPC_ERROR_CREATE(error_name);
+ }
+ *cumulative = grpc_error_add_child(*cumulative, new);
+}
+
+static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_metadata_batch *b) {
call_data *calld = elem->call_data;
+ grpc_error *error = GRPC_ERROR_NONE;
+ static const char *error_name = "Failed processing incoming headers";
- /* Check if it is one of the headers we care about. */
- if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
- md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_METHOD_GET ||
- md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
- md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
- /* swallow it */
- if (md == GRPC_MDELEM_METHOD_POST) {
- calld->seen_method = 1;
+ if (b->idx.named.method != NULL) {
+ if (grpc_mdelem_eq(b->idx.named.method->md, GRPC_MDELEM_METHOD_POST)) {
*calld->recv_idempotent_request = false;
*calld->recv_cacheable_request = false;
- } else if (md == GRPC_MDELEM_METHOD_PUT) {
- calld->seen_method = 1;
+ } else if (grpc_mdelem_eq(b->idx.named.method->md,
+ GRPC_MDELEM_METHOD_PUT)) {
*calld->recv_idempotent_request = true;
- } else if (md == GRPC_MDELEM_METHOD_GET) {
- calld->seen_method = 1;
+ } else if (grpc_mdelem_eq(b->idx.named.method->md,
+ GRPC_MDELEM_METHOD_GET)) {
*calld->recv_cacheable_request = true;
- } else if (md->key == GRPC_MDSTR_SCHEME) {
- calld->seen_scheme = 1;
- } else if (md == GRPC_MDELEM_TE_TRAILERS) {
- calld->seen_te_trailers = 1;
- }
- /* TODO(klempner): Track that we've seen all the headers we should
- require */
- return NULL;
- } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
- const char *value_str = grpc_mdstr_as_c_string(md->value);
- if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
- EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
- (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
- value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
- /* Although the C implementation doesn't (currently) generate them,
- any custom +-suffix is explicitly valid. */
- /* TODO(klempner): We should consider preallocating common values such
- as +proto or +json, or at least stashing them if we see them. */
- /* TODO(klempner): Should we be surfacing this to application code? */
} else {
- /* TODO(klempner): We're currently allowing this, but we shouldn't
- see it without a proxy so log for now. */
- gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str);
+ add_error(error_name, &error,
+ grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
+ b->idx.named.method->md));
+ }
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.method);
+ } else {
+ add_error(error_name, &error,
+ grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
+ GRPC_ERROR_STR_KEY, ":method"));
+ }
+
+ if (b->idx.named.te != NULL) {
+ if (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) {
+ add_error(error_name, &error,
+ grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
+ b->idx.named.te->md));
+ }
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.te);
+ } else {
+ add_error(error_name, &error,
+ grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
+ GRPC_ERROR_STR_KEY, "te"));
+ }
+
+ if (b->idx.named.scheme != NULL) {
+ if (!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTP) &&
+ !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTPS) &&
+ !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_GRPC)) {
+ add_error(error_name, &error,
+ grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
+ b->idx.named.scheme->md));
}
- return NULL;
- } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
- md->key == GRPC_MDSTR_SCHEME) {
- gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
- grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
- /* swallow it and error everything out. */
- /* TODO(klempner): We ought to generate more descriptive error messages
- on the wire here. */
- grpc_call_element_send_cancel(exec_ctx, elem);
- return NULL;
- } else if (md->key == GRPC_MDSTR_PATH) {
- if (calld->seen_path) {
- gpr_log(GPR_ERROR, "Received :path twice");
- return NULL;
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.scheme);
+ } else {
+ add_error(error_name, &error,
+ grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
+ GRPC_ERROR_STR_KEY, ":scheme"));
+ }
+
+ if (b->idx.named.content_type != NULL) {
+ if (!grpc_mdelem_eq(b->idx.named.content_type->md,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
+ if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md),
+ EXPECTED_CONTENT_TYPE,
+ EXPECTED_CONTENT_TYPE_LENGTH) &&
+ (GRPC_SLICE_START_PTR(GRPC_MDVALUE(
+ b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] ==
+ '+' ||
+ GRPC_SLICE_START_PTR(GRPC_MDVALUE(
+ b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] ==
+ ';')) {
+ /* Although the C implementation doesn't (currently) generate them,
+ any custom +-suffix is explicitly valid. */
+ /* TODO(klempner): We should consider preallocating common values such
+ as +proto or +json, or at least stashing them if we see them. */
+ /* TODO(klempner): Should we be surfacing this to application code? */
+ } else {
+ /* TODO(klempner): We're currently allowing this, but we shouldn't
+ see it without a proxy so log for now. */
+ char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.content_type->md),
+ GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "Unexpected content-type '%s'", val);
+ gpr_free(val);
+ }
}
- calld->seen_path = 1;
- return md;
- } else if (md->key == GRPC_MDSTR_AUTHORITY) {
- calld->seen_authority = 1;
- return md;
- } else if (md->key == GRPC_MDSTR_HOST) {
- /* translate host to :authority since :authority may be
- omitted */
- grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
- calld->seen_authority = 1;
- return authority;
- } else if (md->key == GRPC_MDSTR_GRPC_PAYLOAD_BIN) {
- /* Retrieve the payload from the value of the 'grpc-internal-payload-bin'
- header field */
- calld->seen_payload_bin = 1;
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.content_type);
+ }
+
+ if (b->idx.named.path == NULL) {
+ add_error(error_name, &error,
+ grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
+ GRPC_ERROR_STR_KEY, ":path"));
+ }
+
+ if (b->idx.named.host != NULL) {
+ add_error(
+ error_name, &error,
+ grpc_metadata_batch_substitute(
+ exec_ctx, b, b->idx.named.host,
+ grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_ref_internal(GRPC_MDVALUE(b->idx.named.host->md)))));
+ }
+
+ if (b->idx.named.authority == NULL) {
+ add_error(error_name, &error,
+ grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
+ GRPC_ERROR_STR_KEY, ":authority"));
+ }
+
+ if (b->idx.named.grpc_payload_bin != NULL) {
+ calld->seen_payload_bin = true;
grpc_slice_buffer_add(&calld->read_slice_buffer,
- grpc_slice_ref_internal(md->value->slice));
+ grpc_slice_ref_internal(
+ GRPC_MDVALUE(b->idx.named.grpc_payload_bin->md)));
grpc_slice_buffer_stream_init(&calld->read_stream,
&calld->read_slice_buffer, 0);
- return NULL;
- } else {
- return md;
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_payload_bin);
}
+
+ return error;
}
static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -193,49 +232,12 @@ static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
if (err == GRPC_ERROR_NONE) {
- grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
- server_filter, elem);
- /* Have we seen the required http2 transport headers?
- (:method, :scheme, content-type, with :path and :authority covered
- at the channel level right now) */
- if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers &&
- calld->seen_path && calld->seen_authority) {
- /* do nothing */
- } else {
- err = GRPC_ERROR_CREATE("Bad incoming HTTP headers");
- if (!calld->seen_path) {
- err = grpc_error_add_child(err,
- GRPC_ERROR_CREATE("Missing :path header"));
- }
- if (!calld->seen_authority) {
- err = grpc_error_add_child(
- err, GRPC_ERROR_CREATE("Missing :authority header"));
- }
- if (!calld->seen_method) {
- err = grpc_error_add_child(err,
- GRPC_ERROR_CREATE("Missing :method header"));
- }
- if (!calld->seen_scheme) {
- err = grpc_error_add_child(err,
- GRPC_ERROR_CREATE("Missing :scheme header"));
- }
- if (!calld->seen_te_trailers) {
- err = grpc_error_add_child(
- err, GRPC_ERROR_CREATE("Missing te: trailers header"));
- }
- /* Error this call out */
- if (grpc_http_trace) {
- const char *error_str = grpc_error_string(err);
- gpr_log(GPR_ERROR, "Invalid http2 headers: %s", error_str);
- grpc_error_free_string(error_str);
- }
- grpc_call_element_send_cancel(exec_ctx, elem);
- }
+ err = server_filter_incoming_metadata(exec_ctx, elem,
+ calld->recv_initial_metadata);
} else {
GRPC_ERROR_REF(err);
}
- calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err);
- GRPC_ERROR_UNREF(err);
+ grpc_closure_run(exec_ctx, calld->on_done_recv, err);
}
static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -273,13 +275,23 @@ static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
- if (op->send_initial_metadata != NULL && !calld->sent_status) {
- calld->sent_status = 1;
- grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status,
- GRPC_MDELEM_STATUS_200);
- grpc_metadata_batch_add_tail(
- op->send_initial_metadata, &calld->content_type,
- GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+ if (op->send_initial_metadata != NULL) {
+ grpc_error *error = GRPC_ERROR_NONE;
+ static const char *error_name = "Failed sending initial metadata";
+ add_error(error_name, &error, grpc_metadata_batch_add_head(
+ exec_ctx, op->send_initial_metadata,
+ &calld->status, GRPC_MDELEM_STATUS_200));
+ add_error(error_name, &error,
+ grpc_metadata_batch_add_tail(
+ exec_ctx, op->send_initial_metadata, &calld->content_type,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC));
+ add_error(error_name, &error,
+ server_filter_outgoing_metadata(exec_ctx, elem,
+ op->send_initial_metadata));
+ if (error != GRPC_ERROR_NONE) {
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ return;
+ }
}
if (op->recv_initial_metadata) {
@@ -306,8 +318,12 @@ static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
if (op->send_trailing_metadata) {
- grpc_metadata_batch_filter(exec_ctx, op->send_trailing_metadata,
- server_filter_outgoing_metadata, elem);
+ grpc_error *error = server_filter_outgoing_metadata(
+ exec_ctx, elem, op->send_trailing_metadata);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ return;
+ }
}
}
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 862090b371..5e22860cfb 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -58,7 +58,7 @@ static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) {
gpr_free(value);
}
-static const grpc_mdstr_hash_table_vtable message_size_limits_vtable = {
+static const grpc_slice_hash_table_vtable message_size_limits_vtable = {
message_size_limits_free, message_size_limits_copy};
static void* message_size_limits_create_from_json(const grpc_json* json) {
@@ -68,12 +68,16 @@ static void* message_size_limits_create_from_json(const grpc_json* json) {
if (field->key == NULL) continue;
if (strcmp(field->key, "maxRequestMessageBytes") == 0) {
if (max_request_message_bytes >= 0) return NULL; // Duplicate.
- if (field->type != GRPC_JSON_STRING) return NULL;
+ if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) {
+ return NULL;
+ }
max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_request_message_bytes == -1) return NULL;
} else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
if (max_response_message_bytes >= 0) return NULL; // Duplicate.
- if (field->type != GRPC_JSON_STRING) return NULL;
+ if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) {
+ return NULL;
+ }
max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_response_message_bytes == -1) return NULL;
}
@@ -101,7 +105,7 @@ typedef struct channel_data {
int max_send_size;
int max_recv_size;
// Maps path names to message_size_limits structs.
- grpc_mdstr_hash_table* method_limit_table;
+ grpc_slice_hash_table* method_limit_table;
} channel_data;
// Callback invoked when we receive a message. Here we check the max
@@ -142,10 +146,12 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
char* message_string;
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
op->send_message->length, calld->max_send_size);
- grpc_slice message = grpc_slice_from_copied_string(message_string);
+ grpc_transport_stream_op_finish_with_failure(
+ exec_ctx, op, grpc_error_set_int(GRPC_ERROR_CREATE(message_string),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_INVALID_ARGUMENT));
gpr_free(message_string);
- grpc_call_element_send_close_with_message(
- exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message);
+ return;
}
// Inject callback for receiving a message.
if (op->recv_message_ready != NULL) {
@@ -243,7 +249,7 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_element* elem) {
channel_data* chand = elem->channel_data;
- grpc_mdstr_hash_table_unref(exec_ctx, chand->method_limit_table);
+ grpc_slice_hash_table_unref(exec_ctx, chand->method_limit_table);
}
const grpc_channel_filter grpc_message_size_filter = {
diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h
index 1f9cc15f23..58dfe628b4 100644
--- a/src/core/lib/compression/algorithm_metadata.h
+++ b/src/core/lib/compression/algorithm_metadata.h
@@ -38,16 +38,16 @@
#include "src/core/lib/transport/metadata.h"
/** Return compression algorithm based metadata value */
-grpc_mdstr *grpc_compression_algorithm_mdstr(
+grpc_slice grpc_compression_algorithm_slice(
grpc_compression_algorithm algorithm);
/** Return compression algorithm based metadata element (grpc-encoding: xxx) */
-grpc_mdelem *grpc_compression_encoding_mdelem(
+grpc_mdelem grpc_compression_encoding_mdelem(
grpc_compression_algorithm algorithm);
/** Find compression algorithm based on passed in mdstr - returns
* GRPC_COMPRESS_ALGORITHM_COUNT on failure */
-grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
- grpc_mdstr *str);
+grpc_compression_algorithm grpc_compression_algorithm_from_slice(
+ grpc_slice str);
#endif /* GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H */
diff --git a/src/core/lib/compression/compression.c b/src/core/lib/compression/compression.c
index 54efb5e855..ce4f597af5 100644
--- a/src/core/lib/compression/compression.c
+++ b/src/core/lib/compression/compression.c
@@ -41,30 +41,24 @@
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/transport/static_metadata.h"
-int grpc_compression_algorithm_parse(const char *name, size_t name_length,
+int grpc_compression_algorithm_parse(grpc_slice name,
grpc_compression_algorithm *algorithm) {
/* we use strncmp not only because it's safer (even though in this case it
* doesn't matter, given that we are comparing against string literals, but
* because this way we needn't have "name" nil-terminated (useful for slice
* data, for example) */
- GRPC_API_TRACE(
- "grpc_compression_algorithm_parse("
- "name=%*.*s, name_length=%lu, algorithm=%p)",
- 5, ((int)name_length, (int)name_length, name, (unsigned long)name_length,
- algorithm));
- if (name_length == 0) {
- return 0;
- }
- if (strncmp(name, "identity", name_length) == 0) {
+ if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) {
*algorithm = GRPC_COMPRESS_NONE;
- } else if (strncmp(name, "gzip", name_length) == 0) {
+ return 1;
+ } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) {
*algorithm = GRPC_COMPRESS_GZIP;
- } else if (strncmp(name, "deflate", name_length) == 0) {
+ return 1;
+ } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) {
*algorithm = GRPC_COMPRESS_DEFLATE;
+ return 1;
} else {
return 0;
}
- return 1;
}
int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
@@ -87,15 +81,15 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
return 0;
}
-grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
- grpc_mdstr *str) {
- if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE;
- if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE;
- if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP;
+grpc_compression_algorithm grpc_compression_algorithm_from_slice(
+ grpc_slice str) {
+ if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE;
+ if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE;
+ if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP;
return GRPC_COMPRESS_ALGORITHMS_COUNT;
}
-grpc_mdstr *grpc_compression_algorithm_mdstr(
+grpc_slice grpc_compression_algorithm_slice(
grpc_compression_algorithm algorithm) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
@@ -105,12 +99,12 @@ grpc_mdstr *grpc_compression_algorithm_mdstr(
case GRPC_COMPRESS_GZIP:
return GRPC_MDSTR_GZIP;
case GRPC_COMPRESS_ALGORITHMS_COUNT:
- return NULL;
+ return grpc_empty_slice();
}
- return NULL;
+ return grpc_empty_slice();
}
-grpc_mdelem *grpc_compression_encoding_mdelem(
+grpc_mdelem grpc_compression_encoding_mdelem(
grpc_compression_algorithm algorithm) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
@@ -122,7 +116,7 @@ grpc_mdelem *grpc_compression_encoding_mdelem(
default:
break;
}
- return NULL;
+ return GRPC_MDNULL;
}
void grpc_compression_options_init(grpc_compression_options *opts) {
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 440817c5a6..f4f6f3c27a 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -156,7 +156,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
if (error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
- grpc_error_free_string(msg);
+
c->func(exec_ctx, c->arg, NULL);
} else {
grpc_channel_args_destroy(exec_ctx, args->args);
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index da0ec878a3..509c1ff95d 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -34,6 +34,7 @@
#include "src/core/lib/iomgr/closure.h"
#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include "src/core/lib/profiling/timers.h"
@@ -50,20 +51,22 @@ void grpc_closure_list_init(grpc_closure_list *closure_list) {
closure_list->head = closure_list->tail = NULL;
}
-void grpc_closure_list_append(grpc_closure_list *closure_list,
+bool grpc_closure_list_append(grpc_closure_list *closure_list,
grpc_closure *closure, grpc_error *error) {
if (closure == NULL) {
GRPC_ERROR_UNREF(error);
- return;
+ return false;
}
closure->error_data.error = error;
closure->next_data.next = NULL;
- if (closure_list->head == NULL) {
+ bool was_empty = (closure_list->head == NULL);
+ if (was_empty) {
closure_list->head = closure;
} else {
closure_list->tail->next_data.next = closure;
}
closure_list->tail = closure;
+ return was_empty;
}
void grpc_closure_list_fail_all(grpc_closure_list *list,
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index ee386fbc76..2510d50b42 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -66,6 +66,7 @@ typedef struct grpc_closure_scheduler_vtable {
grpc_error *error);
void (*sched)(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error);
+ const char *name;
} grpc_closure_scheduler_vtable;
/** Abstract type that can schedule closures for execution */
@@ -115,8 +116,9 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg,
void grpc_closure_list_init(grpc_closure_list *list);
/** add \a closure to the end of \a list
- and set \a closure's result to \a error */
-void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
+ and set \a closure's result to \a error
+ Returns true if \a list becomes non-empty */
+bool grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
grpc_error *error);
/** force all success bits in \a list to false */
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
index c26a73b2b7..ba6c7087a9 100644
--- a/src/core/lib/iomgr/combiner.c
+++ b/src/core/lib/iomgr/combiner.c
@@ -86,13 +86,17 @@ static void combiner_finally_exec_covered(grpc_exec_ctx *exec_ctx,
grpc_error *error);
static const grpc_closure_scheduler_vtable scheduler_uncovered = {
- combiner_exec_uncovered, combiner_exec_uncovered};
+ combiner_exec_uncovered, combiner_exec_uncovered,
+ "combiner:immediately:uncovered"};
static const grpc_closure_scheduler_vtable scheduler_covered = {
- combiner_exec_covered, combiner_exec_covered};
+ combiner_exec_covered, combiner_exec_covered,
+ "combiner:immediately:covered"};
static const grpc_closure_scheduler_vtable finally_scheduler_uncovered = {
- combiner_finally_exec_uncovered, combiner_finally_exec_uncovered};
+ combiner_finally_exec_uncovered, combiner_finally_exec_uncovered,
+ "combiner:finally:uncovered"};
static const grpc_closure_scheduler_vtable finally_scheduler_covered = {
- combiner_finally_exec_covered, combiner_finally_exec_covered};
+ combiner_finally_exec_covered, combiner_finally_exec_covered,
+ "combiner:finally:covered"};
static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
diff --git a/src/core/lib/iomgr/endpoint.c b/src/core/lib/iomgr/endpoint.c
index 2d300f4560..bf6e98146a 100644
--- a/src/core/lib/iomgr/endpoint.c
+++ b/src/core/lib/iomgr/endpoint.c
@@ -54,8 +54,9 @@ void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx,
ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set);
}
-void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
- ep->vtable->shutdown(exec_ctx, ep);
+void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
+ grpc_error* why) {
+ ep->vtable->shutdown(exec_ctx, ep, why);
}
void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 1609b64f2b..740357ecc5 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -57,7 +57,7 @@ struct grpc_endpoint_vtable {
grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_pollset_set *pollset);
- void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+ void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_error *why);
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
grpc_resource_user *(*get_resource_user)(grpc_endpoint *ep);
char *(*get_peer)(grpc_endpoint *ep);
@@ -96,7 +96,8 @@ void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
/* Causes any pending and future read/write callbacks to run immediately with
success==0 */
-void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_error *why);
void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
/* Add an endpoint to a pollset, so that when the pollset is polled, events from
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index f6bb3a0477..dbe5b139f9 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -33,13 +33,10 @@
#include "src/core/lib/iomgr/error.h"
-#include <inttypes.h>
-#include <stdbool.h>
#include <string.h>
#include <grpc/status.h>
#include <grpc/support/alloc.h>
-#include <grpc/support/avl.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
@@ -48,6 +45,7 @@
#include <grpc/support/log_windows.h>
#endif
+#include "src/core/lib/iomgr/error_internal.h"
#include "src/core/lib/profiling/timers.h"
static void destroy_integer(void *key) {}
@@ -128,6 +126,10 @@ static const char *error_int_name(grpc_error_ints key) {
static const char *error_str_name(grpc_error_strs key) {
switch (key) {
+ case GRPC_ERROR_STR_KEY:
+ return "key";
+ case GRPC_ERROR_STR_VALUE:
+ return "value";
case GRPC_ERROR_STR_DESCRIPTION:
return "description";
case GRPC_ERROR_STR_OS_ERROR:
@@ -160,16 +162,7 @@ static const char *error_time_name(grpc_error_times key) {
GPR_UNREACHABLE_CODE(return "unknown");
}
-struct grpc_error {
- gpr_refcount refs;
- gpr_avl ints;
- gpr_avl strs;
- gpr_avl times;
- gpr_avl errs;
- uintptr_t next_err;
-};
-
-static bool is_special(grpc_error *err) {
+bool grpc_error_is_special(grpc_error *err) {
return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM ||
err == GRPC_ERROR_CANCELLED;
}
@@ -177,7 +170,7 @@ static bool is_special(grpc_error *err) {
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
const char *func) {
- if (is_special(err)) return err;
+ if (grpc_error_is_special(err)) return err;
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err,
err->refs.count, err->refs.count + 1, file, line, func);
gpr_ref(&err->refs);
@@ -185,25 +178,26 @@ grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
}
#else
grpc_error *grpc_error_ref(grpc_error *err) {
- if (is_special(err)) return err;
+ if (grpc_error_is_special(err)) return err;
gpr_ref(&err->refs);
return err;
}
#endif
static void error_destroy(grpc_error *err) {
- GPR_ASSERT(!is_special(err));
+ GPR_ASSERT(!grpc_error_is_special(err));
gpr_avl_unref(err->ints);
gpr_avl_unref(err->strs);
gpr_avl_unref(err->errs);
gpr_avl_unref(err->times);
+ gpr_free((void *)gpr_atm_acq_load(&err->error_string));
gpr_free(err);
}
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
void grpc_error_unref(grpc_error *err, const char *file, int line,
const char *func) {
- if (is_special(err)) return;
+ if (grpc_error_is_special(err)) return;
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err,
err->refs.count, err->refs.count - 1, file, line, func);
if (gpr_unref(&err->refs)) {
@@ -212,7 +206,7 @@ void grpc_error_unref(grpc_error *err, const char *file, int line,
}
#else
void grpc_error_unref(grpc_error *err) {
- if (is_special(err)) return;
+ if (grpc_error_is_special(err)) return;
if (gpr_unref(&err->refs)) {
error_destroy(err);
}
@@ -247,6 +241,7 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc,
err->times = gpr_avl_add(gpr_avl_create(&avl_vtable_times),
(void *)(uintptr_t)GRPC_ERROR_TIME_CREATED,
box_time(gpr_now(GPR_CLOCK_REALTIME)));
+ gpr_atm_no_barrier_store(&err->error_string, 0);
gpr_ref_init(&err->refs, 1);
GPR_TIMER_END("grpc_error_create", 0);
return err;
@@ -255,9 +250,10 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc,
static grpc_error *copy_error_and_unref(grpc_error *in) {
GPR_TIMER_BEGIN("copy_error_and_unref", 0);
grpc_error *out;
- if (is_special(in)) {
+ if (grpc_error_is_special(in)) {
if (in == GRPC_ERROR_NONE)
- out = GRPC_ERROR_CREATE("no error");
+ out = grpc_error_set_int(GRPC_ERROR_CREATE("no error"),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
else if (in == GRPC_ERROR_OOM)
out = GRPC_ERROR_CREATE("oom");
else if (in == GRPC_ERROR_CANCELLED)
@@ -275,6 +271,7 @@ static grpc_error *copy_error_and_unref(grpc_error *in) {
out->strs = gpr_avl_ref(in->strs);
out->errs = gpr_avl_ref(in->errs);
out->times = gpr_avl_ref(in->times);
+ gpr_atm_no_barrier_store(&out->error_string, 0);
out->next_err = in->next_err;
gpr_ref_init(&out->refs, 1);
GRPC_ERROR_UNREF(in);
@@ -292,14 +289,29 @@ grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
return new;
}
+typedef struct {
+ grpc_error *error;
+ grpc_status_code code;
+ const char *msg;
+} special_error_status_map;
+static special_error_status_map error_status_map[] = {
+ {GRPC_ERROR_NONE, GRPC_STATUS_OK, NULL},
+ {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"},
+ {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"},
+};
+
bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
GPR_TIMER_BEGIN("grpc_error_get_int", 0);
void *pp;
- if (is_special(err)) {
- if (err == GRPC_ERROR_CANCELLED && which == GRPC_ERROR_INT_GRPC_STATUS) {
- *p = GRPC_STATUS_CANCELLED;
- GPR_TIMER_END("grpc_error_get_int", 0);
- return true;
+ if (grpc_error_is_special(err)) {
+ if (which == GRPC_ERROR_INT_GRPC_STATUS) {
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
+ if (error_status_map[i].error == err) {
+ if (p != NULL) *p = error_status_map[i].code;
+ GPR_TIMER_END("grpc_error_get_int", 0);
+ return true;
+ }
+ }
}
GPR_TIMER_END("grpc_error_get_int", 0);
return false;
@@ -324,66 +336,17 @@ grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
}
const char *grpc_error_get_str(grpc_error *err, grpc_error_strs which) {
- if (is_special(err)) return NULL;
- return gpr_avl_get(err->strs, (void *)(uintptr_t)which);
-}
-
-typedef struct {
- grpc_error *error;
- grpc_status_code code;
- const char *msg;
-} special_error_status_map;
-static special_error_status_map error_status_map[] = {
- {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""},
- {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "RPC cancelled"},
- {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"},
-};
-
-static grpc_error *recursively_find_error_with_status(grpc_error *error,
- intptr_t *status) {
- // If the error itself has a status code, return it.
- if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, status)) {
- return error;
- }
- // Otherwise, search through its children.
- intptr_t key = 0;
- while (true) {
- grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
- if (child_error == NULL) break;
- grpc_error *result =
- recursively_find_error_with_status(child_error, status);
- if (result != NULL) return result;
- }
- return NULL;
-}
-
-void grpc_error_get_status(grpc_error *error, grpc_status_code *code,
- const char **msg) {
- // Handle special errors via the static map.
- for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); ++i) {
- if (error == error_status_map[i].error) {
- *code = error_status_map[i].code;
- *msg = error_status_map[i].msg;
- return;
+ if (grpc_error_is_special(err)) {
+ if (which == GRPC_ERROR_STR_GRPC_MESSAGE) {
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
+ if (error_status_map[i].error == err) {
+ return error_status_map[i].msg;
+ }
+ }
}
+ return NULL;
}
- // Populate code.
- // Start with the parent error and recurse through the tree of children
- // 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 = recursively_find_error_with_status(error, &status);
- *code = (grpc_status_code)status;
- // Now populate msg.
- // If we found an error with a status code above, use that; otherwise,
- // fall back to using the parent error.
- if (found_error == NULL) found_error = error;
- // If the error has a status message, use it. Otherwise, fall back to
- // the error description.
- *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE);
- if (*msg == NULL) {
- *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION);
- if (*msg == NULL) *msg = "uknown error"; // Just in case.
- }
+ return gpr_avl_get(err->strs, (void *)(uintptr_t)which);
}
grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) {
@@ -535,7 +498,6 @@ static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap,
*first = false;
const char *e = grpc_error_string(n->value);
append_str(e, s, sz, cap);
- grpc_error_free_string(e);
add_errs(n->right, s, sz, cap, first);
}
@@ -557,7 +519,7 @@ static int cmp_kvs(const void *a, const void *b) {
return strcmp(ka->key, kb->key);
}
-static const char *finish_kvs(kv_pairs *kvs) {
+static char *finish_kvs(kv_pairs *kvs) {
char *s = NULL;
size_t sz = 0;
size_t cap = 0;
@@ -578,19 +540,18 @@ static const char *finish_kvs(kv_pairs *kvs) {
return s;
}
-void grpc_error_free_string(const char *str) {
- if (str == no_error_string) return;
- if (str == oom_error_string) return;
- if (str == cancelled_error_string) return;
- gpr_free((char *)str);
-}
-
const char *grpc_error_string(grpc_error *err) {
GPR_TIMER_BEGIN("grpc_error_string", 0);
if (err == GRPC_ERROR_NONE) return no_error_string;
if (err == GRPC_ERROR_OOM) return oom_error_string;
if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
+ void *p = (void *)gpr_atm_acq_load(&err->error_string);
+ if (p != NULL) {
+ GPR_TIMER_END("grpc_error_string", 0);
+ return p;
+ }
+
kv_pairs kvs;
memset(&kvs, 0, sizeof(kvs));
@@ -603,7 +564,13 @@ const char *grpc_error_string(grpc_error *err) {
qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
- const char *out = finish_kvs(&kvs);
+ char *out = finish_kvs(&kvs);
+
+ if (!gpr_atm_rel_cas(&err->error_string, 0, (gpr_atm)out)) {
+ gpr_free(out);
+ out = (char *)gpr_atm_no_barrier_load(&err->error_string);
+ }
+
GPR_TIMER_END("grpc_error_string", 0);
return out;
}
@@ -638,7 +605,6 @@ bool grpc_log_if_error(const char *what, grpc_error *error, const char *file,
if (error == GRPC_ERROR_NONE) return true;
const char *msg = grpc_error_string(error);
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
- grpc_error_free_string(msg);
GRPC_ERROR_UNREF(error);
return false;
}
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index f3f3b80a09..ffacdac393 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -124,7 +124,11 @@ typedef enum {
/// filename that we were trying to read/write when this error occurred
GRPC_ERROR_STR_FILENAME,
/// which data was queued for writing when the error occurred
- GRPC_ERROR_STR_QUEUED_BUFFERS
+ GRPC_ERROR_STR_QUEUED_BUFFERS,
+ /// key associated with the error
+ GRPC_ERROR_STR_KEY,
+ /// value associated with the error
+ GRPC_ERROR_STR_VALUE,
} grpc_error_strs;
typedef enum {
@@ -141,7 +145,6 @@ typedef enum {
#define GRPC_ERROR_CANCELLED ((grpc_error *)4)
const char *grpc_error_string(grpc_error *error);
-void grpc_error_free_string(const char *str);
/// Create an error - but use GRPC_ERROR_CREATE instead
grpc_error *grpc_error_create(const char *file, int line, const char *desc,
@@ -189,12 +192,6 @@ grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
/// Caller does NOT own return value.
const char *grpc_error_get_str(grpc_error *error, grpc_error_strs which);
-/// 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
-/// through child errors until it finds the first one with these attributes.
-void grpc_error_get_status(grpc_error *error, grpc_status_code *code,
- const char **msg);
-
/// Add a child error: an error that is believed to have contributed to this
/// error occurring. Allows root causing high level errors from lower level
/// errors that contributed to them.
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
new file mode 100644
index 0000000000..1c89ead4ed
--- /dev/null
+++ b/src/core/lib/iomgr/error_internal.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H
+#define GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <grpc/support/avl.h>
+
+struct grpc_error {
+ gpr_refcount refs;
+ gpr_avl ints;
+ gpr_avl strs;
+ gpr_avl times;
+ gpr_avl errs;
+ uintptr_t next_err;
+ gpr_atm error_string;
+};
+
+bool grpc_error_is_special(grpc_error *err);
+
+#endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 2a6956ae54..51842fc208 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -143,6 +143,7 @@ struct grpc_fd {
/* Indicates that the fd is shutdown and that any pending read/write closures
should fail */
bool shutdown;
+ grpc_error *shutdown_error; /* reason for shutdown: set iff shutdown==true */
/* The fd is either closed or we relinquished control of it. In either cases,
this indicates that the 'fd' on this structure is no longer valid */
@@ -321,7 +322,7 @@ gpr_atm g_epoll_sync;
#endif /* defined(GRPC_TSAN) */
static const grpc_closure_scheduler_vtable workqueue_scheduler_vtable = {
- workqueue_enqueue, workqueue_enqueue};
+ workqueue_enqueue, workqueue_enqueue, "workqueue"};
static void pi_add_ref(polling_island *pi);
static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi);
@@ -907,6 +908,7 @@ static void unref_by(grpc_fd *fd, int n) {
fd->freelist_next = fd_freelist;
fd_freelist = fd;
grpc_iomgr_unregister_object(&fd->iomgr_object);
+ if (fd->shutdown) GRPC_ERROR_UNREF(fd->shutdown_error);
gpr_mu_unlock(&fd_freelist_mu);
} else {
@@ -1058,11 +1060,11 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
GRPC_ERROR_UNREF(error);
}
-static grpc_error *fd_shutdown_error(bool shutdown) {
- if (!shutdown) {
+static grpc_error *fd_shutdown_error(grpc_fd *fd) {
+ if (!fd->shutdown) {
return GRPC_ERROR_NONE;
} else {
- return GRPC_ERROR_CREATE("FD shutdown");
+ return GRPC_ERROR_CREATE_REFERENCING("FD shutdown", &fd->shutdown_error, 1);
}
}
@@ -1076,7 +1078,7 @@ static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
} else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY;
- grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown));
+ grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd));
} else {
/* upcallptr was set to a different closure. This is an error! */
gpr_log(GPR_ERROR,
@@ -1098,7 +1100,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0;
} else {
/* waiting ==> queue closure */
- grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown));
+ grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd));
*st = CLOSURE_NOT_READY;
return 1;
}
@@ -1123,17 +1125,20 @@ static bool fd_is_shutdown(grpc_fd *fd) {
}
/* Might be called multiple times */
-static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
gpr_mu_lock(&fd->po.mu);
/* Do the actual shutdown only once */
if (!fd->shutdown) {
fd->shutdown = true;
+ fd->shutdown_error = why;
shutdown(fd->fd, SHUT_RDWR);
/* Flush any pending read and write closures. Since fd->shutdown is 'true'
at this point, the closures would be called with 'success = false' */
set_ready_locked(exec_ctx, fd, &fd->read_closure);
set_ready_locked(exec_ctx, fd, &fd->write_closure);
+ } else {
+ GRPC_ERROR_UNREF(why);
}
gpr_mu_unlock(&fd->po.mu);
}
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index 9477ac3688..ca12932219 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -82,6 +82,7 @@ struct grpc_fd {
int shutdown;
int closed;
int released;
+ grpc_error *shutdown_error;
/* The watcher list.
@@ -306,6 +307,7 @@ static void unref_by(grpc_fd *fd, int n) {
if (old == n) {
gpr_mu_destroy(&fd->mu);
grpc_iomgr_unregister_object(&fd->iomgr_object);
+ if (fd->shutdown) GRPC_ERROR_UNREF(fd->shutdown_error);
gpr_free(fd);
} else {
GPR_ASSERT(old > n);
@@ -444,11 +446,11 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#endif
-static grpc_error *fd_shutdown_error(bool shutdown) {
- if (!shutdown) {
+static grpc_error *fd_shutdown_error(grpc_fd *fd) {
+ if (!fd->shutdown) {
return GRPC_ERROR_NONE;
} else {
- return GRPC_ERROR_CREATE("FD shutdown");
+ return GRPC_ERROR_CREATE_REFERENCING("FD shutdown", &fd->shutdown_error, 1);
}
}
@@ -462,7 +464,7 @@ static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
} else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY;
- grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown));
+ grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd));
maybe_wake_one_watcher_locked(fd);
} else {
/* upcallptr was set to a different closure. This is an error! */
@@ -485,7 +487,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0;
} else {
/* waiting ==> queue closure */
- grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown));
+ grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd));
*st = CLOSURE_NOT_READY;
return 1;
}
@@ -496,15 +498,18 @@ static void set_read_notifier_pollset_locked(
fd->read_notifier_pollset = read_notifier_pollset;
}
-static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
gpr_mu_lock(&fd->mu);
/* only shutdown once */
if (!fd->shutdown) {
fd->shutdown = 1;
+ fd->shutdown_error = why;
/* signal read/write closed to OS so that future operations fail */
shutdown(fd->fd, SHUT_RDWR);
set_ready_locked(exec_ctx, fd, &fd->read_closure);
set_ready_locked(exec_ctx, fd, &fd->write_closure);
+ } else {
+ GRPC_ERROR_UNREF(why);
}
gpr_mu_unlock(&fd->mu);
}
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index 2975d619e1..5bb55631d6 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -52,6 +52,8 @@
* tests */
grpc_poll_function_type grpc_poll_function = poll;
+grpc_wakeup_fd grpc_global_wakeup_fd;
+
static const grpc_event_engine_vtable *g_event_engine;
static const char *g_poll_strategy_name = NULL;
@@ -160,8 +162,8 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
g_event_engine->fd_orphan(exec_ctx, fd, on_done, release_fd, reason);
}
-void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- g_event_engine->fd_shutdown(exec_ctx, fd);
+void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
+ g_event_engine->fd_shutdown(exec_ctx, fd, why);
}
bool grpc_fd_is_shutdown(grpc_fd *fd) {
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 1068a4bad5..a589efdeec 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -51,7 +51,7 @@ typedef struct grpc_event_engine_vtable {
int (*fd_wrapped_fd)(grpc_fd *fd);
void (*fd_orphan)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
int *release_fd, const char *reason);
- void (*fd_shutdown)(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
+ void (*fd_shutdown)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why);
void (*fd_notify_on_read)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure);
void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
@@ -140,7 +140,7 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
bool grpc_fd_is_shutdown(grpc_fd *fd);
/* Cause any current and future callbacks to fail. */
-void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
+void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why);
/* Register read interest, causing read_cb to be called once when fd becomes
readable, on deadline specified by deadline, or on shutdown triggered by
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
index 6aa788f8e5..83bb436bd0 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -42,11 +42,16 @@
#include "src/core/lib/profiling/timers.h"
bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) {
- if (!exec_ctx->cached_ready_to_finish) {
- exec_ctx->cached_ready_to_finish = exec_ctx->check_ready_to_finish(
- exec_ctx, exec_ctx->check_ready_to_finish_arg);
+ if ((exec_ctx->flags & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0) {
+ if (exec_ctx->check_ready_to_finish(exec_ctx,
+ exec_ctx->check_ready_to_finish_arg)) {
+ exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED;
+ return true;
+ }
+ return false;
+ } else {
+ return true;
}
- return exec_ctx->cached_ready_to_finish;
}
bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) {
@@ -82,7 +87,7 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
}
void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
- exec_ctx->cached_ready_to_finish = true;
+ exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED;
grpc_exec_ctx_flush(exec_ctx);
}
@@ -101,6 +106,6 @@ void grpc_exec_ctx_global_init(void) {}
void grpc_exec_ctx_global_shutdown(void) {}
static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
- exec_ctx_run, exec_ctx_sched};
+ exec_ctx_run, exec_ctx_sched, "exec_ctx"};
static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable};
grpc_closure_scheduler *grpc_schedule_on_exec_ctx = &exec_ctx_scheduler;
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index e566f1b3e8..f99a0fee5f 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -43,6 +43,13 @@
typedef struct grpc_workqueue grpc_workqueue;
typedef struct grpc_combiner grpc_combiner;
+/* This exec_ctx is ready to return: either pre-populated, or cached as soon as
+ the finish_check returns true */
+#define GRPC_EXEC_CTX_FLAG_IS_FINISHED 1
+/* The exec_ctx's thread is (potentially) owned by a call or channel: care
+ should be given to not delete said call/channel from this exec_ctx */
+#define GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP 2
+
/** Execution context.
* A bag of data that collects information along a callstack.
* Generally created at public API entry points, and passed down as
@@ -63,36 +70,26 @@ typedef struct grpc_combiner grpc_combiner;
* - Instances are always passed as the first argument to a function that
* takes it, and always as a pointer (grpc_exec_ctx is never copied).
*/
-#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
struct grpc_exec_ctx {
grpc_closure_list closure_list;
/** currently active combiner: updated only via combiner.c */
grpc_combiner *active_combiner;
/** last active combiner in the active combiner list */
grpc_combiner *last_combiner;
- bool cached_ready_to_finish;
+ uintptr_t flags;
void *check_ready_to_finish_arg;
bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
};
/* initializer for grpc_exec_ctx:
prefer to use GRPC_EXEC_CTX_INIT whenever possible */
-#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
- { GRPC_CLOSURE_LIST_INIT, NULL, NULL, false, finish_check_arg, finish_check }
-#else
-struct grpc_exec_ctx {
- bool cached_ready_to_finish;
- void *check_ready_to_finish_arg;
- bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
-};
-#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
- { false, finish_check_arg, finish_check }
-#endif
+#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \
+ { GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, finish_check_arg, finish_check }
/* initialize an execution context at the top level of an API call into grpc
(this is safe to use elsewhere, though possibly not as efficient) */
#define GRPC_EXEC_CTX_INIT \
- GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_always_ready_to_finish, NULL)
+ GRPC_EXEC_CTX_INITIALIZER(GRPC_EXEC_CTX_FLAG_IS_FINISHED, NULL, NULL)
extern grpc_closure_scheduler *grpc_schedule_on_exec_ctx;
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
index 852775564f..a5b62aa888 100644
--- a/src/core/lib/iomgr/executor.c
+++ b/src/core/lib/iomgr/executor.c
@@ -158,7 +158,7 @@ void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx) {
gpr_mu_destroy(&g_executor.mu);
}
-static const grpc_closure_scheduler_vtable executor_vtable = {executor_push,
- executor_push};
+static const grpc_closure_scheduler_vtable executor_vtable = {
+ executor_push, executor_push, "executor"};
static grpc_closure_scheduler executor_scheduler = {&executor_vtable};
grpc_closure_scheduler *grpc_executor_scheduler = &executor_scheduler;
diff --git a/src/core/lib/iomgr/load_file.c b/src/core/lib/iomgr/load_file.c
index 217bc5da59..f40c8b28cc 100644
--- a/src/core/lib/iomgr/load_file.c
+++ b/src/core/lib/iomgr/load_file.c
@@ -47,7 +47,7 @@ grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
grpc_slice *output) {
unsigned char *contents = NULL;
size_t contents_size = 0;
- grpc_slice result = gpr_empty_slice();
+ grpc_slice result = grpc_empty_slice();
FILE *file;
size_t bytes_read = 0;
grpc_error *error = GRPC_ERROR_NONE;
diff --git a/src/core/lib/iomgr/network_status_tracker.c b/src/core/lib/iomgr/network_status_tracker.c
index a5ca9ed2c3..1601a39002 100644
--- a/src/core/lib/iomgr/network_status_tracker.c
+++ b/src/core/lib/iomgr/network_status_tracker.c
@@ -117,7 +117,8 @@ void grpc_network_status_shutdown_all_endpoints() {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
for (endpoint_ll_node *curr = head; curr != NULL; curr = curr->next) {
- curr->ep->vtable->shutdown(&exec_ctx, curr->ep);
+ curr->ep->vtable->shutdown(&exec_ctx, curr->ep,
+ GRPC_ERROR_CREATE("Network unavailable"));
}
gpr_mu_unlock(&g_endpoint_mutex);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 0286309921..2cc979467f 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -33,6 +33,8 @@
#include "src/core/lib/iomgr/resource_quota.h"
+#include <limits.h>
+#include <stdint.h>
#include <string.h>
#include <grpc/support/alloc.h>
@@ -44,6 +46,8 @@
int grpc_resource_quota_trace = 0;
+#define MEMORY_USAGE_ESTIMATION_MAX 65536
+
/* Internal linked list pointers for a resource user */
typedef struct {
grpc_resource_user *next;
@@ -126,9 +130,12 @@ struct grpc_resource_quota {
/* refcount */
gpr_refcount refs;
+ /* estimate of current memory usage
+ scaled to the range [0..RESOURCE_USAGE_ESTIMATION_MAX] */
+ gpr_atm memory_usage_estimation;
+
/* Master combiner lock: all activity on a quota executes under this combiner
- * (so no mutex is needed for this data structure)
- */
+ * (so no mutex is needed for this data structure) */
grpc_combiner *combiner;
/* Size of the resource quota */
int64_t size;
@@ -269,6 +276,16 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_NONE);
}
+/* update the atomically available resource estimate - use no barriers since
+ timeliness of delivery really doesn't matter much */
+static void rq_update_estimate(grpc_resource_quota *resource_quota) {
+ gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation,
+ (gpr_atm)((1.0 -
+ ((double)resource_quota->free_pool) /
+ ((double)resource_quota->size)) *
+ MEMORY_USAGE_ESTIMATION_MAX));
+}
+
/* returns true if all allocations are completed */
static bool rq_alloc(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota) {
@@ -281,6 +298,7 @@ static bool rq_alloc(grpc_exec_ctx *exec_ctx,
int64_t amt = -resource_user->free_pool;
resource_user->free_pool = 0;
resource_quota->free_pool -= amt;
+ rq_update_estimate(resource_quota);
if (grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, "RQ %s %s: grant alloc %" PRId64
" bytes; rq_free_pool -> %" PRId64,
@@ -315,6 +333,7 @@ static bool rq_reclaim_from_per_user_free_pool(
int64_t amt = resource_user->free_pool;
resource_user->free_pool = 0;
resource_quota->free_pool += amt;
+ rq_update_estimate(resource_quota);
if (grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64
" bytes; rq_free_pool -> %" PRId64,
@@ -378,11 +397,15 @@ static void ru_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
}
}
+static const grpc_slice_refcount_vtable ru_slice_vtable = {
+ ru_slice_ref, ru_slice_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
static grpc_slice ru_slice_create(grpc_resource_user *resource_user,
size_t size) {
ru_slice_refcount *rc = gpr_malloc(sizeof(ru_slice_refcount) + size);
- rc->base.ref = ru_slice_ref;
- rc->base.unref = ru_slice_unref;
+ rc->base.vtable = &ru_slice_vtable;
+ rc->base.sub_refcount = &rc->base;
gpr_ref_init(&rc->refs, 1);
rc->resource_user = resource_user;
rc->size = size;
@@ -527,6 +550,7 @@ static void rq_resize(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
int64_t delta = a->size - a->resource_quota->size;
a->resource_quota->size += delta;
a->resource_quota->free_pool += delta;
+ rq_update_estimate(a->resource_quota);
rq_step_sched(exec_ctx, a->resource_quota);
grpc_resource_quota_unref_internal(exec_ctx, a->resource_quota);
gpr_free(a);
@@ -553,6 +577,7 @@ grpc_resource_quota *grpc_resource_quota_create(const char *name) {
resource_quota->size = INT64_MAX;
resource_quota->step_scheduled = false;
resource_quota->reclaiming = false;
+ gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0);
if (name != NULL) {
resource_quota->name = gpr_strdup(name);
} else {
@@ -598,6 +623,13 @@ void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) {
grpc_resource_quota_ref_internal(resource_quota);
}
+double grpc_resource_quota_get_memory_pressure(
+ grpc_resource_quota *resource_quota) {
+ return ((double)(gpr_atm_no_barrier_load(
+ &resource_quota->memory_usage_estimation))) /
+ ((double)MEMORY_USAGE_ESTIMATION_MAX);
+}
+
/* Public API */
void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
size_t size) {
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index d1127ce9ea..b9f62cbf83 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -84,6 +84,12 @@ void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *grpc_resource_quota_from_channel_args(
const grpc_channel_args *channel_args);
+/* Return a number indicating current memory pressure:
+ 0.0 ==> no memory usage
+ 1.0 ==> maximum memory usage */
+double grpc_resource_quota_get_memory_pressure(
+ grpc_resource_quota *resource_quota);
+
typedef struct grpc_resource_user grpc_resource_user;
grpc_resource_user *grpc_resource_user_create(
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index 9a77c92016..0144192b71 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -118,11 +118,11 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
str);
- grpc_error_free_string(str);
}
gpr_mu_lock(&ac->mu);
if (ac->fd != NULL) {
- grpc_fd_shutdown(exec_ctx, ac->fd);
+ grpc_fd_shutdown(exec_ctx, ac->fd,
+ GRPC_ERROR_CREATE("connect() timed out"));
}
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
@@ -178,7 +178,6 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s",
ac->addr_str, str);
- grpc_error_free_string(str);
}
gpr_mu_lock(&ac->mu);
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index 1e84ec3a1e..c8dc9e64bd 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -135,12 +135,10 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
/* Tries to issue one async connection, then schedules both an IOCP
notification request for the connection, and one timeout alert. */
-void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
- grpc_endpoint **endpoint,
- grpc_pollset_set *interested_parties,
- const grpc_channel_args *channel_args,
- const grpc_resolved_address *addr,
- gpr_timespec deadline) {
+static void tcp_client_connect_impl(
+ grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_endpoint **endpoint,
+ grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
+ const grpc_resolved_address *addr, gpr_timespec deadline) {
SOCKET sock = INVALID_SOCKET;
BOOL success;
int status;
@@ -252,4 +250,21 @@ failure:
grpc_closure_sched(exec_ctx, on_done, final_error);
}
+// overridden by api_fuzzer.c
+void (*grpc_tcp_client_connect_impl)(
+ grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
+ grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
+ const grpc_resolved_address *addr,
+ gpr_timespec deadline) = tcp_client_connect_impl;
+
+void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+ grpc_endpoint **ep,
+ grpc_pollset_set *interested_parties,
+ const grpc_channel_args *channel_args,
+ const grpc_resolved_address *addr,
+ gpr_timespec deadline) {
+ grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
+ channel_args, addr, deadline);
+}
+
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index ece44978b0..a4381f8fc9 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -119,9 +119,10 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error);
-static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_error *why) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- grpc_fd_shutdown(exec_ctx, tcp->em_fd);
+ grpc_fd_shutdown(exec_ctx, tcp->em_fd, why);
grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
}
@@ -181,7 +182,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
size_t i;
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "read: error=%s", str);
- grpc_error_free_string(str);
+
for (i = 0; i < tcp->incoming_buffer->count; i++) {
char *dump = grpc_dump_slice(tcp->incoming_buffer->slices[i],
GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -435,7 +436,6 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
if (grpc_tcp_trace) {
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "write: %s", str);
- grpc_error_free_string(str);
}
grpc_closure_run(exec_ctx, cb, error);
@@ -485,7 +485,6 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
if (grpc_tcp_trace) {
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "write: %s", str);
- grpc_error_free_string(str);
}
grpc_closure_sched(exec_ctx, cb, error);
}
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 20efb678b2..e9e7511c9c 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -276,7 +276,8 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
if (s->active_ports) {
grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) {
- grpc_fd_shutdown(exec_ctx, sp->emfd);
+ grpc_fd_shutdown(exec_ctx, sp->emfd,
+ GRPC_ERROR_CREATE("Server destroyed"));
}
gpr_mu_unlock(&s->mu);
} else {
@@ -773,7 +774,8 @@ void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
if (s->active_ports) {
grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) {
- grpc_fd_shutdown(exec_ctx, sp->emfd);
+ grpc_fd_shutdown(exec_ctx, sp->emfd,
+ GRPC_ERROR_CREATE("Server shutdown"));
}
}
gpr_mu_unlock(&s->mu);
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index dafe851ce8..bd4b9b2df1 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -343,7 +343,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
if (error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
- grpc_error_free_string(msg);
+
gpr_mu_unlock(&sp->server->mu);
return;
}
diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c
index 3ddc79706b..5fb398c50b 100644
--- a/src/core/lib/iomgr/tcp_uv.c
+++ b/src/core/lib/iomgr/tcp_uv.c
@@ -48,6 +48,7 @@
#include "src/core/lib/iomgr/network_status_tracker.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/tcp_uv.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
@@ -156,7 +157,7 @@ static void read_callback(uv_stream_t *stream, ssize_t nread,
size_t i;
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "read: error=%s", str);
- grpc_error_free_string(str);
+
for (i = 0; i < tcp->read_slices->count; i++) {
char *dump = grpc_dump_slice(tcp->read_slices->slices[i],
GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -297,13 +298,15 @@ static void uv_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
static void shutdown_callback(uv_shutdown_t *req, int status) {}
-static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_error *why) {
grpc_tcp *tcp = (grpc_tcp *)ep;
if (!tcp->shutting_down) {
tcp->shutting_down = true;
uv_shutdown_t *req = &tcp->shutdown_req;
uv_shutdown(req, (uv_stream_t *)tcp->handle, shutdown_callback);
}
+ GRPC_ERROR_UNREF(why);
}
static void uv_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index 84f791ba07..6c413971e3 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -116,6 +116,7 @@ typedef struct grpc_tcp {
to protect ourselves when requesting a shutdown. */
gpr_mu mu;
int shutting_down;
+ grpc_error *shutdown_error;
char *peer_string;
} grpc_tcp;
@@ -125,6 +126,7 @@ static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
gpr_mu_destroy(&tcp->mu);
gpr_free(tcp->peer_string);
grpc_resource_user_unref(exec_ctx, tcp->resource_user);
+ if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error);
gpr_free(tcp);
}
@@ -182,7 +184,10 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
grpc_slice_buffer_add(tcp->read_slices, sub);
} else {
grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
- error = GRPC_ERROR_CREATE("End of TCP stream");
+ error = tcp->shutting_down
+ ? GRPC_ERROR_CREATE_REFERENCING("TCP stream shutting down",
+ &tcp->shutdown_error, 1)
+ : GRPC_ERROR_CREATE("End of TCP stream");
}
}
}
@@ -203,8 +208,9 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
WSABUF buffer;
if (tcp->shutting_down) {
- grpc_closure_sched(exec_ctx, cb,
- GRPC_ERROR_CREATE("TCP socket is shutting down"));
+ grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_CREATE_REFERENCING(
+ "TCP socket is shutting down",
+ &tcp->shutdown_error, 1));
return;
}
@@ -291,8 +297,9 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
size_t len;
if (tcp->shutting_down) {
- grpc_closure_sched(exec_ctx, cb,
- GRPC_ERROR_CREATE("TCP socket is shutting down"));
+ grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_CREATE_REFERENCING(
+ "TCP socket is shutting down",
+ &tcp->shutdown_error, 1));
return;
}
@@ -373,12 +380,18 @@ static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
we're not going to protect against these. However the IO Completion Port
callback will happen from another thread, so we need to protect against
concurrent access of the data structure in that regard. */
-static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_error *why) {
grpc_tcp *tcp = (grpc_tcp *)ep;
gpr_mu_lock(&tcp->mu);
/* At that point, what may happen is that we're already inside the IOCP
callback. See the comments in on_read and on_write. */
- tcp->shutting_down = 1;
+ if (!tcp->shutting_down) {
+ tcp->shutting_down = 1;
+ tcp->shutdown_error = why;
+ } else {
+ GRPC_ERROR_UNREF(why);
+ }
grpc_winsocket_shutdown(tcp->socket);
gpr_mu_unlock(&tcp->mu);
grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index dfbd295c91..02a194c982 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -76,8 +76,10 @@ struct grpc_udp_listener {
grpc_udp_server *server;
grpc_resolved_address addr;
grpc_closure read_closure;
+ grpc_closure write_closure;
grpc_closure destroyed_closure;
grpc_udp_server_read_cb read_cb;
+ grpc_udp_server_write_cb write_cb;
grpc_udp_server_orphan_cb orphan_cb;
struct grpc_udp_listener *next;
@@ -203,7 +205,8 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
for (sp = s->head; sp; sp = sp->next) {
GPR_ASSERT(sp->orphan_cb);
sp->orphan_cb(sp->emfd);
- grpc_fd_shutdown(exec_ctx, sp->emfd);
+ grpc_fd_shutdown(exec_ctx, sp->emfd,
+ GRPC_ERROR_CREATE("Server destroyed"));
}
gpr_mu_unlock(&s->mu);
} else {
@@ -303,9 +306,33 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_mu_unlock(&sp->server->mu);
}
+static void on_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ grpc_udp_listener *sp = arg;
+
+ gpr_mu_lock(&(sp->server->mu));
+ if (error != GRPC_ERROR_NONE) {
+ if (0 == --sp->server->active_ports) {
+ gpr_mu_unlock(&sp->server->mu);
+ deactivated_all_ports(exec_ctx, sp->server);
+ } else {
+ gpr_mu_unlock(&sp->server->mu);
+ }
+ return;
+ }
+
+ /* Tell the registered callback that the socket is writeable. */
+ GPR_ASSERT(sp->write_cb);
+ sp->write_cb(exec_ctx, sp->emfd);
+
+ /* Re-arm the notification event so we get another chance to write. */
+ grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure);
+ gpr_mu_unlock(&sp->server->mu);
+}
+
static int add_socket_to_server(grpc_udp_server *s, int fd,
const grpc_resolved_address *addr,
grpc_udp_server_read_cb read_cb,
+ grpc_udp_server_write_cb write_cb,
grpc_udp_server_orphan_cb orphan_cb) {
grpc_udp_listener *sp;
int port;
@@ -332,6 +359,7 @@ static int add_socket_to_server(grpc_udp_server *s, int fd,
sp->emfd = grpc_fd_create(fd, name);
memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
sp->read_cb = read_cb;
+ sp->write_cb = write_cb;
sp->orphan_cb = orphan_cb;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
@@ -344,6 +372,7 @@ static int add_socket_to_server(grpc_udp_server *s, int fd,
int grpc_udp_server_add_port(grpc_udp_server *s,
const grpc_resolved_address *addr,
grpc_udp_server_read_cb read_cb,
+ grpc_udp_server_write_cb write_cb,
grpc_udp_server_orphan_cb orphan_cb) {
grpc_udp_listener *sp;
int allocated_port1 = -1;
@@ -390,7 +419,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
// TODO(rjshade): Test and propagate the returned grpc_error*:
GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP,
&dsmode, &fd));
- allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb);
+ allocated_port1 =
+ add_socket_to_server(s, fd, addr, read_cb, write_cb, orphan_cb);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
}
@@ -412,7 +442,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
addr = &addr4_copy;
}
- allocated_port2 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb);
+ allocated_port2 =
+ add_socket_to_server(s, fd, addr, read_cb, write_cb, orphan_cb);
done:
gpr_free(allocated_addr);
@@ -450,6 +481,10 @@ void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
grpc_schedule_on_exec_ctx);
grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
+ grpc_closure_init(&sp->write_closure, on_write, sp,
+ grpc_schedule_on_exec_ctx);
+ grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure);
+
s->active_ports++;
sp = sp->next;
}
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index f3c466a031..ce068cbf04 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -49,6 +49,10 @@ typedef struct grpc_udp_server grpc_udp_server;
typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
struct grpc_server *server);
+/* Called when the socket is writeable. */
+typedef void (*grpc_udp_server_write_cb)(grpc_exec_ctx *exec_ctx,
+ grpc_fd *emfd);
+
/* Called when the grpc_fd is about to be orphaned (and the FD closed). */
typedef void (*grpc_udp_server_orphan_cb)(grpc_fd *emfd);
@@ -75,6 +79,7 @@ int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index);
int grpc_udp_server_add_port(grpc_udp_server *s,
const grpc_resolved_address *addr,
grpc_udp_server_read_cb read_cb,
+ grpc_udp_server_write_cb write_cb,
grpc_udp_server_orphan_cb orphan_cb);
void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server,
diff --git a/src/core/lib/iomgr/unix_sockets_posix.c b/src/core/lib/iomgr/unix_sockets_posix.c
index 030acd9811..1233cec04e 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.c
+++ b/src/core/lib/iomgr/unix_sockets_posix.c
@@ -45,6 +45,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
void grpc_create_socketpair_if_unix(int sv[2]) {
GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
@@ -53,7 +54,16 @@ void grpc_create_socketpair_if_unix(int sv[2]) {
grpc_error *grpc_resolve_unix_domain_address(const char *name,
grpc_resolved_addresses **addrs) {
struct sockaddr_un *un;
-
+ if (strlen(name) > GPR_ARRAY_SIZE(((struct sockaddr_un *)0)->sun_path) - 1) {
+ char *err_msg;
+ grpc_error *err;
+ gpr_asprintf(&err_msg,
+ "Path name should not have more than %" PRIuPTR " characters.",
+ GPR_ARRAY_SIZE(un->sun_path) - 1);
+ err = GRPC_ERROR_CREATE(err_msg);
+ gpr_free(err_msg);
+ return err;
+ }
*addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
(*addrs)->naddrs = 1;
(*addrs)->addrs = gpr_malloc(sizeof(grpc_resolved_address));
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c
index d6e1fe3dcf..a098741b70 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.c
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c
@@ -177,7 +177,7 @@ static grpc_error *create_default_creds_from_path(
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_call_credentials *result = NULL;
- grpc_slice creds_data = gpr_empty_slice();
+ grpc_slice creds_data = grpc_empty_slice();
grpc_error *error = GRPC_ERROR_NONE;
if (creds_path == NULL) {
error = GRPC_ERROR_CREATE("creds_path unset");
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c
index f90d7dce83..7bc5dfb403 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.c
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c
@@ -42,7 +42,9 @@
#include <grpc/support/sync.h>
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/validate_metadata.h"
typedef struct {
void *user_data;
@@ -63,7 +65,9 @@ static void plugin_md_request_metadata_ready(void *request,
grpc_status_code status,
const char *error_details) {
/* called from application code */
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INITIALIZER(
+ GRPC_EXEC_CTX_FLAG_IS_FINISHED | GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP,
+ NULL, NULL);
grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
if (status != GRPC_STATUS_OK) {
if (error_details != NULL) {
@@ -77,13 +81,14 @@ static void plugin_md_request_metadata_ready(void *request,
bool seen_illegal_header = false;
grpc_credentials_md *md_array = NULL;
for (i = 0; i < num_md; i++) {
- if (!grpc_header_key_is_legal(md[i].key, strlen(md[i].key))) {
- gpr_log(GPR_ERROR, "Plugin added invalid metadata key: %s", md[i].key);
+ if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin",
+ grpc_validate_header_key_is_legal(md[i].key))) {
seen_illegal_header = true;
break;
- } else if (!grpc_is_binary_header(md[i].key, strlen(md[i].key)) &&
- !grpc_header_nonbin_value_is_legal(md[i].value,
- md[i].value_length)) {
+ } else if (!grpc_is_binary_header(md[i].key) &&
+ !GRPC_LOG_IF_ERROR(
+ "validate_metadata_from_plugin",
+ grpc_validate_header_nonbin_value_is_legal(md[i].value))) {
gpr_log(GPR_ERROR, "Plugin added invalid metadata value.");
seen_illegal_header = true;
break;
@@ -95,9 +100,8 @@ static void plugin_md_request_metadata_ready(void *request,
} else if (num_md > 0) {
md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
for (i = 0; i < num_md; i++) {
- md_array[i].key = grpc_slice_from_copied_string(md[i].key);
- md_array[i].value =
- grpc_slice_from_copied_buffer(md[i].value, md[i].value_length);
+ md_array[i].key = grpc_slice_ref_internal(md[i].key);
+ md_array[i].value = grpc_slice_ref_internal(md[i].value);
}
r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK,
NULL);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index b7f6fd23e3..cf056e8008 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -45,6 +45,7 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -54,8 +55,10 @@
/* We can have a per-call credentials. */
typedef struct {
grpc_call_credentials *creds;
- grpc_mdstr *host;
- grpc_mdstr *method;
+ bool have_host;
+ bool have_method;
+ grpc_slice host;
+ grpc_slice method;
/* pollset{_set} bound to this call; if we need to make external
network requests, they should be done under a pollset added to this
pollset_set so that work can progress when this call wants work to progress
@@ -89,14 +92,12 @@ static void reset_auth_metadata_context(
auth_md_context->channel_auth_context = NULL;
}
-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_slice error_slice = grpc_slice_from_copied_string(error_msg);
- grpc_transport_stream_op_add_close(exec_ctx, &calld->op, status,
- &error_slice);
- grpc_call_next_op(exec_ctx, elem, &calld->op);
+static void add_error(grpc_error **combined, grpc_error *error) {
+ if (error == GRPC_ERROR_NONE) return;
+ if (*combined == GRPC_ERROR_NONE) {
+ *combined = GRPC_ERROR_CREATE("Client auth metadata plugin error");
+ }
+ *combined = grpc_error_add_child(*combined, error);
}
static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -110,30 +111,37 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_metadata_batch *mdb;
size_t i;
reset_auth_metadata_context(&calld->auth_md_context);
+ grpc_error *error = GRPC_ERROR_NONE;
if (status != GRPC_CREDENTIALS_OK) {
- bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
- (error_details != NULL && strlen(error_details) > 0)
- ? error_details
- : "Credentials failed to get metadata.");
- return;
+ error = grpc_error_set_int(
+ GRPC_ERROR_CREATE(error_details != NULL && strlen(error_details) > 0
+ ? error_details
+ : "Credentials failed to get metadata."),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED);
+ } else {
+ 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++) {
+ add_error(&error,
+ grpc_metadata_batch_add_tail(
+ exec_ctx, mdb, &calld->md_links[i],
+ grpc_mdelem_from_slices(
+ exec_ctx, grpc_slice_ref_internal(md_elems[i].key),
+ grpc_slice_ref_internal(md_elems[i].value))));
+ }
}
- 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(exec_ctx,
- grpc_slice_ref_internal(md_elems[i].key),
- grpc_slice_ref_internal(md_elems[i].value)));
+ if (error == GRPC_ERROR_NONE) {
+ grpc_call_next_op(exec_ctx, elem, op);
+ } else {
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
}
- grpc_call_next_op(exec_ctx, elem, op);
}
void build_auth_metadata_context(grpc_security_connector *sc,
grpc_auth_context *auth_context,
call_data *calld) {
- char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
+ char *service = grpc_slice_to_c_string(calld->method);
char *last_slash = strrchr(service, '/');
char *method_name = NULL;
char *service_url = NULL;
@@ -149,14 +157,15 @@ void build_auth_metadata_context(grpc_security_connector *sc,
method_name = gpr_strdup(last_slash + 1);
}
if (method_name == NULL) method_name = gpr_strdup("");
+ char *host = grpc_slice_to_c_string(calld->host);
gpr_asprintf(&service_url, "%s://%s%s",
- sc->url_scheme == NULL ? "" : sc->url_scheme,
- grpc_mdstr_as_c_string(calld->host), service);
+ sc->url_scheme == NULL ? "" : sc->url_scheme, host, service);
calld->auth_md_context.service_url = service_url;
calld->auth_md_context.method_name = method_name;
calld->auth_md_context.channel_auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
gpr_free(service);
+ gpr_free(host);
}
static void send_security_metadata(grpc_exec_ctx *exec_ctx,
@@ -180,8 +189,12 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
ctx->creds, NULL);
if (calld->creds == NULL) {
- bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
- "Incompatible credentials set on channel and call.");
+ 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 {
@@ -207,9 +220,14 @@ static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
send_security_metadata(exec_ctx, elem, &calld->op);
} else {
char *error_msg;
+ char *host = grpc_slice_to_c_string(calld->host);
gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
- grpc_mdstr_as_c_string(calld->host));
- bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, error_msg);
+ host);
+ gpr_free(host);
+ grpc_call_element_signal_error(
+ exec_ctx, elem, grpc_error_set_int(GRPC_ERROR_CREATE(error_msg),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNAUTHENTICATED));
gpr_free(error_msg);
}
}
@@ -247,23 +265,30 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
if (op->send_initial_metadata != NULL) {
for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
- grpc_mdelem *md = l->md;
+ 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(exec_ctx, calld->host);
- calld->host = GRPC_MDSTR_REF(md->value);
- } else if (md->key == GRPC_MDSTR_PATH) {
- if (calld->method != NULL) GRPC_MDSTR_UNREF(exec_ctx, calld->method);
- calld->method = GRPC_MDSTR_REF(md->value);
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) {
+ if (calld->have_host) {
+ grpc_slice_unref_internal(exec_ctx, calld->host);
+ }
+ calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
+ calld->have_host = true;
+ } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) {
+ if (calld->have_method) {
+ grpc_slice_unref_internal(exec_ctx, calld->method);
+ }
+ calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
+ calld->have_method = true;
}
}
- if (calld->host != NULL) {
- const char *call_host = grpc_mdstr_as_c_string(calld->host);
+ if (calld->have_host) {
+ char *call_host = grpc_slice_to_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);
+ gpr_free(call_host);
GPR_TIMER_END("auth_start_transport_op", 0);
return; /* early exit */
}
@@ -296,11 +321,11 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
call_data *calld = elem->call_data;
grpc_call_credentials_unref(exec_ctx, calld->creds);
- if (calld->host != NULL) {
- GRPC_MDSTR_UNREF(exec_ctx, calld->host);
+ if (calld->have_host) {
+ grpc_slice_unref_internal(exec_ctx, calld->host);
}
- if (calld->method != NULL) {
- GRPC_MDSTR_UNREF(exec_ctx, calld->method);
+ if (calld->have_method) {
+ grpc_slice_unref_internal(exec_ctx, calld->method);
}
reset_auth_metadata_context(&calld->auth_md_context);
}
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 18a7a6f7e7..7d58843d69 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -341,10 +341,10 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
}
-static void endpoint_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_endpoint *secure_ep) {
+static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
+ grpc_error *why) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
- grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep);
+ grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep, why);
}
static void endpoint_destroy(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index 5aa26e0577..b09127811b 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -601,7 +601,7 @@ static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer};
static grpc_slice compute_default_pem_root_certs_once(void) {
- grpc_slice result = gpr_empty_slice();
+ grpc_slice result = grpc_empty_slice();
/* First try to load the roots from the environment. */
char *default_root_certs_path =
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
index 5e75856c7a..bb8a3bf6cd 100644
--- a/src/core/lib/security/transport/security_handshaker.c
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -124,13 +124,13 @@ static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx,
}
const char *msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg);
- grpc_error_free_string(msg);
+
if (!h->shutdown) {
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
- grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, h->args->endpoint, GRPC_ERROR_REF(error));
// Not shutting down, so the write failed. Clean up before
// invoking the callback.
cleanup_args_for_failure_locked(exec_ctx, h);
@@ -347,15 +347,17 @@ static void security_handshaker_destroy(grpc_exec_ctx *exec_ctx,
}
static void security_handshaker_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_handshaker *handshaker) {
+ grpc_handshaker *handshaker,
+ grpc_error *why) {
security_handshaker *h = (security_handshaker *)handshaker;
gpr_mu_lock(&h->mu);
if (!h->shutdown) {
h->shutdown = true;
- grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
+ grpc_endpoint_shutdown(exec_ctx, h->args->endpoint, GRPC_ERROR_REF(why));
cleanup_args_for_failure_locked(exec_ctx, h);
}
gpr_mu_unlock(&h->mu);
+ GRPC_ERROR_UNREF(why);
}
static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx,
@@ -417,7 +419,10 @@ static void fail_handshaker_destroy(grpc_exec_ctx *exec_ctx,
}
static void fail_handshaker_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_handshaker *handshaker) {}
+ grpc_handshaker *handshaker,
+ grpc_error *why) {
+ GRPC_ERROR_UNREF(why);
+}
static void fail_handshaker_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker,
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 5e98ba895d..36e81d6501 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -33,12 +33,13 @@
#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/auth_filters.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
+#include "src/core/lib/slice/slice_internal.h"
typedef struct call_data {
grpc_metadata_batch *recv_initial_metadata;
@@ -67,48 +68,34 @@ static grpc_metadata_array metadata_batch_to_md_array(
grpc_metadata_array_init(&result);
for (l = batch->list.head; l != NULL; l = l->next) {
grpc_metadata *usr_md = NULL;
- grpc_mdelem *md = l->md;
- grpc_mdstr *key = md->key;
- grpc_mdstr *value = md->value;
+ grpc_mdelem md = l->md;
+ grpc_slice key = GRPC_MDKEY(md);
+ grpc_slice value = GRPC_MDVALUE(md);
if (result.count == result.capacity) {
result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
result.metadata =
gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
}
usr_md = &result.metadata[result.count++];
- usr_md->key = grpc_mdstr_as_c_string(key);
- usr_md->value = grpc_mdstr_as_c_string(value);
- usr_md->value_length = GRPC_SLICE_LENGTH(value->slice);
+ usr_md->key = grpc_slice_ref_internal(key);
+ usr_md->value = grpc_slice_ref_internal(value);
}
return result;
}
-static grpc_mdelem *remove_consumed_md(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_mdelem *md) {
+static grpc_filtered_mdelem remove_consumed_md(grpc_exec_ctx *exec_ctx,
+ void *user_data,
+ grpc_mdelem md) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
size_t i;
for (i = 0; i < calld->num_consumed_md; i++) {
const grpc_metadata *consumed_md = &calld->consumed_md[i];
- /* Maybe we could do a pointer comparison but we do not have any guarantee
- that the metadata processor used the same pointers for consumed_md in the
- callback. */
- if (GRPC_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
- GRPC_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
- continue;
- }
- if (memcmp(GRPC_SLICE_START_PTR(md->key->slice), consumed_md->key,
- GRPC_SLICE_LENGTH(md->key->slice)) == 0 &&
- memcmp(GRPC_SLICE_START_PTR(md->value->slice), consumed_md->value,
- GRPC_SLICE_LENGTH(md->value->slice)) == 0) {
- return NULL; /* Delete. */
- }
+ if (grpc_slice_eq(GRPC_MDKEY(md), consumed_md->key) &&
+ grpc_slice_eq(GRPC_MDVALUE(md), consumed_md->value))
+ return GRPC_FILTERED_REMOVE();
}
- return md;
-}
-
-static void destroy_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
- gpr_free(arg);
+ return GRPC_FILTERED_MDELEM(md);
}
/* called from application code */
@@ -130,29 +117,33 @@ static void on_md_processing_done(
if (status == GRPC_STATUS_OK) {
calld->consumed_md = consumed_md;
calld->num_consumed_md = num_consumed_md;
- grpc_metadata_batch_filter(&exec_ctx, calld->recv_initial_metadata,
- remove_consumed_md, elem);
+ /* TODO(ctiller): propagate error */
+ GRPC_LOG_IF_ERROR(
+ "grpc_metadata_batch_filter",
+ grpc_metadata_batch_filter(&exec_ctx, calld->recv_initial_metadata,
+ remove_consumed_md, elem,
+ "Response metadata filtering error"));
+ for (size_t i = 0; i < calld->md.count; i++) {
+ grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].key);
+ grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].value);
+ }
grpc_metadata_array_destroy(&calld->md);
grpc_closure_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE);
} else {
- grpc_slice message;
- grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op));
- memset(close_op, 0, sizeof(*close_op));
+ for (size_t i = 0; i < calld->md.count; i++) {
+ grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].key);
+ grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].value);
+ }
grpc_metadata_array_destroy(&calld->md);
error_details = error_details != NULL
? error_details
: "Authentication metadata processing failed.";
- message = grpc_slice_from_copied_string(error_details);
calld->transport_op->send_initial_metadata = NULL;
if (calld->transport_op->send_message != NULL) {
grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
calld->transport_op->send_message = NULL;
}
calld->transport_op->send_trailing_metadata = NULL;
- close_op->on_complete =
- grpc_closure_create(destroy_op, close_op, grpc_schedule_on_exec_ctx);
- grpc_transport_stream_op_add_close(&exec_ctx, close_op, status, &message);
- grpc_call_next_op(&exec_ctx, elem, close_op);
grpc_closure_sched(&exec_ctx, calld->on_done_recv,
grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
GRPC_ERROR_INT_GRPC_STATUS, status));
diff --git a/src/core/lib/security/util/b64.c b/src/core/lib/security/util/b64.c
index bbd7e335a6..09c8213131 100644
--- a/src/core/lib/security/util/b64.c
+++ b/src/core/lib/security/util/b64.c
@@ -232,5 +232,5 @@ grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64,
fail:
grpc_slice_unref_internal(exec_ctx, result);
- return gpr_empty_slice();
+ return grpc_empty_slice();
}
diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c
index 76118102ec..1cddf062cd 100644
--- a/src/core/lib/slice/slice.c
+++ b/src/core/lib/slice/slice.c
@@ -41,23 +41,30 @@
#include "src/core/lib/iomgr/exec_ctx.h"
-grpc_slice gpr_empty_slice(void) {
+char *grpc_slice_to_c_string(grpc_slice slice) {
+ char *out = gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1);
+ memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
+ out[GRPC_SLICE_LENGTH(slice)] = 0;
+ return out;
+}
+
+grpc_slice grpc_empty_slice(void) {
grpc_slice out;
- out.refcount = 0;
+ out.refcount = NULL;
out.data.inlined.length = 0;
return out;
}
grpc_slice grpc_slice_ref_internal(grpc_slice slice) {
if (slice.refcount) {
- slice.refcount->ref(slice.refcount);
+ slice.refcount->vtable->ref(slice.refcount);
}
return slice;
}
void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
if (slice.refcount) {
- slice.refcount->unref(exec_ctx, slice.refcount);
+ slice.refcount->vtable->unref(exec_ctx, slice.refcount);
}
}
@@ -78,16 +85,24 @@ void grpc_slice_unref(grpc_slice slice) {
static void noop_ref(void *unused) {}
static void noop_unref(grpc_exec_ctx *exec_ctx, void *unused) {}
-static grpc_slice_refcount noop_refcount = {noop_ref, noop_unref};
+static const grpc_slice_refcount_vtable noop_refcount_vtable = {
+ noop_ref, noop_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable,
+ &noop_refcount};
-grpc_slice grpc_slice_from_static_string(const char *s) {
+grpc_slice grpc_slice_from_static_buffer(const void *s, size_t len) {
grpc_slice slice;
slice.refcount = &noop_refcount;
slice.data.refcounted.bytes = (uint8_t *)s;
- slice.data.refcounted.length = strlen(s);
+ slice.data.refcounted.length = len;
return slice;
}
+grpc_slice grpc_slice_from_static_string(const char *s) {
+ return grpc_slice_from_static_buffer(s, strlen(s));
+}
+
/* grpc_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {
@@ -110,14 +125,18 @@ static void new_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
}
}
+static const grpc_slice_refcount_vtable new_slice_vtable = {
+ new_slice_ref, new_slice_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
grpc_slice grpc_slice_new_with_user_data(void *p, size_t len,
void (*destroy)(void *),
void *user_data) {
grpc_slice slice;
new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
gpr_ref_init(&rc->refs, 1);
- rc->rc.ref = new_slice_ref;
- rc->rc.unref = new_slice_unref;
+ rc->rc.vtable = &new_slice_vtable;
+ rc->rc.sub_refcount = &rc->rc;
rc->user_destroy = destroy;
rc->user_data = user_data;
@@ -155,14 +174,18 @@ static void new_with_len_unref(grpc_exec_ctx *exec_ctx, void *p) {
}
}
+static const grpc_slice_refcount_vtable new_with_len_vtable = {
+ new_with_len_ref, new_with_len_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
grpc_slice grpc_slice_new_with_len(void *p, size_t len,
void (*destroy)(void *, size_t)) {
grpc_slice slice;
new_with_len_slice_refcount *rc =
gpr_malloc(sizeof(new_with_len_slice_refcount));
gpr_ref_init(&rc->refs, 1);
- rc->rc.ref = new_with_len_ref;
- rc->rc.unref = new_with_len_unref;
+ rc->rc.vtable = &new_with_len_vtable;
+ rc->rc.sub_refcount = &rc->rc;
rc->user_destroy = destroy;
rc->user_data = p;
rc->user_length = len;
@@ -200,6 +223,10 @@ static void malloc_unref(grpc_exec_ctx *exec_ctx, void *p) {
}
}
+static const grpc_slice_refcount_vtable malloc_vtable = {
+ malloc_ref, malloc_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
grpc_slice grpc_slice_malloc(size_t length) {
grpc_slice slice;
@@ -219,8 +246,8 @@ grpc_slice grpc_slice_malloc(size_t length) {
this reference. */
gpr_ref_init(&rc->refs, 1);
- rc->base.ref = malloc_ref;
- rc->base.unref = malloc_unref;
+ rc->base.vtable = &malloc_vtable;
+ rc->base.sub_refcount = &rc->base;
/* Build up the slice to be returned. */
/* The slices refcount points back to the allocated block. */
@@ -247,7 +274,7 @@ grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
GPR_ASSERT(source.data.refcounted.length >= end);
/* Build the result */
- subset.refcount = source.refcount;
+ subset.refcount = source.refcount->sub_refcount;
/* Point into the source array */
subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
subset.data.refcounted.length = end - begin;
@@ -273,7 +300,7 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
} else {
subset = grpc_slice_sub_no_ref(source, begin, end);
/* Bump the refcount */
- subset.refcount->ref(subset.refcount);
+ subset.refcount->vtable->ref(subset.refcount);
}
return subset;
}
@@ -300,13 +327,14 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) {
tail_length);
} else {
/* Build the result */
- tail.refcount = source->refcount;
+ tail.refcount = source->refcount->sub_refcount;
/* Bump the refcount */
- tail.refcount->ref(tail.refcount);
+ tail.refcount->vtable->ref(tail.refcount);
/* Point into the source array */
tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
tail.data.refcounted.length = tail_length;
}
+ source->refcount = source->refcount->sub_refcount;
source->data.refcounted.length = split;
}
@@ -332,18 +360,20 @@ grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) {
head.refcount = NULL;
head.data.inlined.length = (uint8_t)split;
memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
+ source->refcount = source->refcount->sub_refcount;
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
} else {
GPR_ASSERT(source->data.refcounted.length >= split);
/* Build the result */
- head.refcount = source->refcount;
+ head.refcount = source->refcount->sub_refcount;
/* Bump the refcount */
- head.refcount->ref(head.refcount);
+ head.refcount->vtable->ref(head.refcount);
/* Point into the source array */
head.data.refcounted.bytes = source->data.refcounted.bytes;
head.data.refcounted.length = split;
+ source->refcount = source->refcount->sub_refcount;
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
}
@@ -351,6 +381,19 @@ grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) {
return head;
}
+int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
+ return GRPC_SLICE_LENGTH(a) == GRPC_SLICE_LENGTH(b) &&
+ 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
+ GRPC_SLICE_LENGTH(a));
+}
+
+int grpc_slice_eq(grpc_slice a, grpc_slice b) {
+ if (a.refcount && b.refcount && a.refcount->vtable == b.refcount->vtable) {
+ return a.refcount->vtable->eq(a, b);
+ }
+ return grpc_slice_default_eq_impl(a, b);
+}
+
int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
int d = (int)(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
if (d != 0) return d;
@@ -367,8 +410,55 @@ int grpc_slice_str_cmp(grpc_slice a, const char *b) {
int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
if (a.refcount == NULL || b.refcount == NULL) {
- return grpc_slice_cmp(a, b) == 0;
+ return grpc_slice_eq(a, b);
}
return a.data.refcounted.length == b.data.refcounted.length &&
a.data.refcounted.bytes == b.data.refcounted.bytes;
}
+
+int grpc_slice_buf_start_eq(grpc_slice a, const void *b, size_t len) {
+ if (GRPC_SLICE_LENGTH(a) < len) return 0;
+ return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
+}
+
+int grpc_slice_rchr(grpc_slice s, char c) {
+ const char *b = (const char *)GRPC_SLICE_START_PTR(s);
+ int i;
+ for (i = (int)GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--)
+ ;
+ return i;
+}
+
+int grpc_slice_chr(grpc_slice s, char c) {
+ const char *b = (const char *)GRPC_SLICE_START_PTR(s);
+ const char *p = memchr(b, c, GRPC_SLICE_LENGTH(s));
+ return p == NULL ? -1 : (int)(p - b);
+}
+
+int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
+ size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
+ const uint8_t *haystack_bytes = GRPC_SLICE_START_PTR(haystack);
+ size_t needle_len = GRPC_SLICE_LENGTH(needle);
+ const uint8_t *needle_bytes = GRPC_SLICE_START_PTR(needle);
+
+ if (haystack_len == 0 || needle_len == 0) return -1;
+ if (haystack_len < needle_len) return -1;
+ if (haystack_len == needle_len)
+ return grpc_slice_eq(haystack, needle) ? 0 : -1;
+ if (needle_len == 1) return grpc_slice_chr(haystack, (char)*needle_bytes);
+
+ const uint8_t *last = haystack_bytes + haystack_len - needle_len;
+ for (const uint8_t *cur = haystack_bytes; cur != last; ++cur) {
+ if (0 == memcmp(cur, needle_bytes, needle_len)) {
+ return (int)(cur - haystack_bytes);
+ }
+ }
+ return -1;
+}
+
+grpc_slice grpc_slice_dup(grpc_slice a) {
+ grpc_slice copy = grpc_slice_malloc(GRPC_SLICE_LENGTH(a));
+ memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
+ GRPC_SLICE_LENGTH(a));
+ return copy;
+}
diff --git a/src/core/lib/transport/mdstr_hash_table.c b/src/core/lib/slice/slice_hash_table.c
index 2791bf653b..46f807f4a5 100644
--- a/src/core/lib/transport/mdstr_hash_table.c
+++ b/src/core/lib/slice/slice_hash_table.c
@@ -29,7 +29,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-#include "src/core/lib/transport/mdstr_hash_table.h"
+#include "src/core/lib/slice/slice_hash_table.h"
#include <stdbool.h>
#include <string.h>
@@ -37,70 +37,79 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/metadata.h"
-struct grpc_mdstr_hash_table {
+struct grpc_slice_hash_table {
gpr_refcount refs;
size_t size;
- grpc_mdstr_hash_table_entry* entries;
+ grpc_slice_hash_table_entry* entries;
};
+static bool is_empty(grpc_slice_hash_table_entry* entry) {
+ return entry->vtable == NULL;
+}
+
// Helper function for insert and get operations that performs quadratic
// probing (https://en.wikipedia.org/wiki/Quadratic_probing).
-static size_t grpc_mdstr_hash_table_find_index(
- const grpc_mdstr_hash_table* table, const grpc_mdstr* key,
- bool find_empty) {
+static size_t grpc_slice_hash_table_find_index(
+ const grpc_slice_hash_table* table, const grpc_slice key, bool find_empty) {
+ size_t hash = grpc_slice_hash(key);
for (size_t i = 0; i < table->size; ++i) {
- const size_t idx = (key->hash + i * i) % table->size;
- if (table->entries[idx].key == NULL) return find_empty ? idx : table->size;
- if (table->entries[idx].key == key) return idx;
+ const size_t idx = (hash + i * i) % table->size;
+ if (is_empty(&table->entries[idx])) {
+ return find_empty ? idx : table->size;
+ }
+ if (grpc_slice_eq(table->entries[idx].key, key)) {
+ return idx;
+ }
}
return table->size; // Not found.
}
-static void grpc_mdstr_hash_table_add(
- grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value,
- const grpc_mdstr_hash_table_vtable* vtable) {
+static void grpc_slice_hash_table_add(
+ grpc_slice_hash_table* table, grpc_slice key, void* value,
+ const grpc_slice_hash_table_vtable* vtable) {
GPR_ASSERT(value != NULL);
const size_t idx =
- grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */);
+ grpc_slice_hash_table_find_index(table, key, true /* find_empty */);
GPR_ASSERT(idx != table->size); // Table should never be full.
- grpc_mdstr_hash_table_entry* entry = &table->entries[idx];
- entry->key = GRPC_MDSTR_REF(key);
+ grpc_slice_hash_table_entry* entry = &table->entries[idx];
+ entry->key = grpc_slice_ref_internal(key);
entry->value = vtable->copy_value(value);
entry->vtable = vtable;
}
-grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
- size_t num_entries, grpc_mdstr_hash_table_entry* entries) {
- grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table));
+grpc_slice_hash_table* grpc_slice_hash_table_create(
+ size_t num_entries, grpc_slice_hash_table_entry* entries) {
+ grpc_slice_hash_table* table = gpr_malloc(sizeof(*table));
memset(table, 0, sizeof(*table));
gpr_ref_init(&table->refs, 1);
// Quadratic probing gets best performance when the table is no more
// than half full.
table->size = num_entries * 2;
- const size_t entry_size = sizeof(grpc_mdstr_hash_table_entry) * table->size;
+ const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size;
table->entries = gpr_malloc(entry_size);
memset(table->entries, 0, entry_size);
for (size_t i = 0; i < num_entries; ++i) {
- grpc_mdstr_hash_table_entry* entry = &entries[i];
- grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable);
+ grpc_slice_hash_table_entry* entry = &entries[i];
+ grpc_slice_hash_table_add(table, entry->key, entry->value, entry->vtable);
}
return table;
}
-grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) {
+grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
if (table != NULL) gpr_ref(&table->refs);
return table;
}
-void grpc_mdstr_hash_table_unref(grpc_exec_ctx* exec_ctx,
- grpc_mdstr_hash_table* table) {
+void grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx,
+ grpc_slice_hash_table* table) {
if (table != NULL && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->size; ++i) {
- grpc_mdstr_hash_table_entry* entry = &table->entries[i];
- if (entry->key != NULL) {
- GRPC_MDSTR_UNREF(exec_ctx, entry->key);
+ grpc_slice_hash_table_entry* entry = &table->entries[i];
+ if (!is_empty(entry)) {
+ grpc_slice_unref_internal(exec_ctx, entry->key);
entry->vtable->destroy_value(exec_ctx, entry->value);
}
}
@@ -109,10 +118,10 @@ void grpc_mdstr_hash_table_unref(grpc_exec_ctx* exec_ctx,
}
}
-void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
- const grpc_mdstr* key) {
+void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
+ const grpc_slice key) {
const size_t idx =
- grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */);
+ grpc_slice_hash_table_find_index(table, key, false /* find_empty */);
if (idx == table->size) return NULL; // Not found.
return table->entries[idx].value;
}
diff --git a/src/core/lib/transport/mdstr_hash_table.h b/src/core/lib/slice/slice_hash_table.h
index 57f497ee27..d0c27122d7 100644
--- a/src/core/lib/transport/mdstr_hash_table.h
+++ b/src/core/lib/slice/slice_hash_table.h
@@ -29,8 +29,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H
-#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H
+#ifndef GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H
+#define GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H
#include "src/core/lib/transport/metadata.h"
@@ -40,38 +40,38 @@
* (https://en.wikipedia.org/wiki/Open_addressing) with quadratic
* probing (https://en.wikipedia.org/wiki/Quadratic_probing).
*
- * The keys are \a grpc_mdstr objects. The values are arbitrary pointers
+ * The keys are \a grpc_slice objects. The values are arbitrary pointers
* with a common vtable.
*
* Hash tables are intentionally immutable, to avoid the need for locking.
*/
-typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table;
+typedef struct grpc_slice_hash_table grpc_slice_hash_table;
-typedef struct grpc_mdstr_hash_table_vtable {
- void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value);
- void* (*copy_value)(void* value);
-} grpc_mdstr_hash_table_vtable;
+typedef struct grpc_slice_hash_table_vtable {
+ void (*destroy_value)(grpc_exec_ctx *exec_ctx, void *value);
+ void *(*copy_value)(void *value);
+} grpc_slice_hash_table_vtable;
-typedef struct grpc_mdstr_hash_table_entry {
- grpc_mdstr* key;
- void* value; /* Must not be NULL. */
- const grpc_mdstr_hash_table_vtable* vtable;
-} grpc_mdstr_hash_table_entry;
+typedef struct grpc_slice_hash_table_entry {
+ grpc_slice key;
+ void *value; /* Must not be NULL. */
+ const grpc_slice_hash_table_vtable *vtable;
+} grpc_slice_hash_table_entry;
/** Creates a new hash table of containing \a entries, which is an array
of length \a num_entries.
Creates its own copy of all keys and values from \a entries. */
-grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
- size_t num_entries, grpc_mdstr_hash_table_entry* entries);
+grpc_slice_hash_table *grpc_slice_hash_table_create(
+ size_t num_entries, grpc_slice_hash_table_entry *entries);
-grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table);
-void grpc_mdstr_hash_table_unref(grpc_exec_ctx* exec_ctx,
- grpc_mdstr_hash_table* table);
+grpc_slice_hash_table *grpc_slice_hash_table_ref(grpc_slice_hash_table *table);
+void grpc_slice_hash_table_unref(grpc_exec_ctx *exec_ctx,
+ grpc_slice_hash_table *table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
-void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
- const grpc_mdstr* key);
+void *grpc_slice_hash_table_get(const grpc_slice_hash_table *table,
+ const grpc_slice key);
-#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */
diff --git a/src/core/lib/slice/slice_intern.c b/src/core/lib/slice/slice_intern.c
new file mode 100644
index 0000000000..7cbd17bffd
--- /dev/null
+++ b/src/core/lib/slice/slice_intern.c
@@ -0,0 +1,344 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/slice/slice_internal.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/iomgr_internal.h" /* for iomgr_abort_on_leaks() */
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/support/murmur_hash.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#define LOG2_SHARD_COUNT 5
+#define SHARD_COUNT (1 << LOG2_SHARD_COUNT)
+#define INITIAL_SHARD_CAPACITY 8
+
+#define TABLE_IDX(hash, capacity) (((hash) >> LOG2_SHARD_COUNT) % (capacity))
+#define SHARD_IDX(hash) ((hash) & ((1 << LOG2_SHARD_COUNT) - 1))
+
+typedef struct interned_slice_refcount {
+ grpc_slice_refcount base;
+ grpc_slice_refcount sub;
+ size_t length;
+ gpr_atm refcnt;
+ uint32_t hash;
+ struct interned_slice_refcount *bucket_next;
+} interned_slice_refcount;
+
+typedef struct slice_shard {
+ gpr_mu mu;
+ interned_slice_refcount **strs;
+ size_t count;
+ size_t capacity;
+} slice_shard;
+
+/* hash seed: decided at initialization time */
+static uint32_t g_hash_seed;
+static int g_forced_hash_seed = 0;
+
+static slice_shard g_shards[SHARD_COUNT];
+
+typedef struct {
+ uint32_t hash;
+ uint32_t idx;
+} static_metadata_hash_ent;
+
+static static_metadata_hash_ent
+ static_metadata_hash[4 * GRPC_STATIC_MDSTR_COUNT];
+static uint32_t max_static_metadata_hash_probe;
+static uint32_t static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
+
+static void interned_slice_ref(void *p) {
+ interned_slice_refcount *s = p;
+ GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) > 0);
+}
+
+static void interned_slice_destroy(interned_slice_refcount *s) {
+ slice_shard *shard = &g_shards[SHARD_IDX(s->hash)];
+ gpr_mu_lock(&shard->mu);
+ GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
+ interned_slice_refcount **prev_next;
+ interned_slice_refcount *cur;
+ for (prev_next = &shard->strs[TABLE_IDX(s->hash, shard->capacity)],
+ cur = *prev_next;
+ cur != s; prev_next = &cur->bucket_next, cur = cur->bucket_next)
+ ;
+ *prev_next = cur->bucket_next;
+ shard->count--;
+ gpr_free(s);
+ gpr_mu_unlock(&shard->mu);
+}
+
+static void interned_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
+ interned_slice_refcount *s = p;
+ if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
+ interned_slice_destroy(s);
+ }
+}
+
+static void interned_slice_sub_ref(void *p) {
+ interned_slice_ref(((char *)p) - offsetof(interned_slice_refcount, sub));
+}
+
+static void interned_slice_sub_unref(grpc_exec_ctx *exec_ctx, void *p) {
+ interned_slice_unref(exec_ctx,
+ ((char *)p) - offsetof(interned_slice_refcount, sub));
+}
+
+static uint32_t interned_slice_hash(grpc_slice slice) {
+ interned_slice_refcount *s = (interned_slice_refcount *)slice.refcount;
+ return s->hash;
+}
+
+static int interned_slice_eq(grpc_slice a, grpc_slice b) {
+ return a.refcount == b.refcount;
+}
+
+static const grpc_slice_refcount_vtable interned_slice_vtable = {
+ interned_slice_ref, interned_slice_unref, interned_slice_eq,
+ interned_slice_hash};
+static const grpc_slice_refcount_vtable interned_slice_sub_vtable = {
+ interned_slice_sub_ref, interned_slice_sub_unref,
+ grpc_slice_default_eq_impl, grpc_slice_default_hash_impl};
+
+static void grow_shard(slice_shard *shard) {
+ size_t capacity = shard->capacity * 2;
+ size_t i;
+ interned_slice_refcount **strtab;
+ interned_slice_refcount *s, *next;
+
+ GPR_TIMER_BEGIN("grow_strtab", 0);
+
+ strtab = gpr_malloc(sizeof(interned_slice_refcount *) * capacity);
+ memset(strtab, 0, sizeof(interned_slice_refcount *) * capacity);
+
+ for (i = 0; i < shard->capacity; i++) {
+ for (s = shard->strs[i]; s; s = next) {
+ size_t idx = TABLE_IDX(s->hash, capacity);
+ next = s->bucket_next;
+ s->bucket_next = strtab[idx];
+ strtab[idx] = s;
+ }
+ }
+
+ gpr_free(shard->strs);
+ shard->strs = strtab;
+ shard->capacity = capacity;
+
+ GPR_TIMER_END("grow_strtab", 0);
+}
+
+static grpc_slice materialize(interned_slice_refcount *s) {
+ grpc_slice slice;
+ slice.refcount = &s->base;
+ slice.data.refcounted.bytes = (uint8_t *)(s + 1);
+ slice.data.refcounted.length = s->length;
+ return slice;
+}
+
+uint32_t grpc_slice_default_hash_impl(grpc_slice s) {
+ return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
+ g_hash_seed);
+}
+
+uint32_t grpc_static_slice_hash(grpc_slice s) {
+ return static_metadata_hash_values[GRPC_STATIC_METADATA_INDEX(s)];
+}
+
+int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
+ return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
+}
+
+uint32_t grpc_slice_hash(grpc_slice s) {
+ return s.refcount == NULL ? grpc_slice_default_hash_impl(s)
+ : s.refcount->vtable->hash(s);
+}
+
+grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
+ bool *returned_slice_is_different) {
+ if (GRPC_IS_STATIC_METADATA_STRING(slice)) {
+ return slice;
+ }
+
+ uint32_t hash = grpc_slice_hash(slice);
+ for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
+ static_metadata_hash_ent ent =
+ static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
+ if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
+ grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) {
+ *returned_slice_is_different = true;
+ return grpc_static_slice_table[ent.idx];
+ }
+ }
+
+ return slice;
+}
+
+bool grpc_slice_is_interned(grpc_slice slice) {
+ return (slice.refcount && slice.refcount->vtable == &interned_slice_vtable) ||
+ GRPC_IS_STATIC_METADATA_STRING(slice);
+}
+
+grpc_slice grpc_slice_intern(grpc_slice slice) {
+ if (GRPC_IS_STATIC_METADATA_STRING(slice)) {
+ return slice;
+ }
+
+ uint32_t hash = grpc_slice_hash(slice);
+ for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
+ static_metadata_hash_ent ent =
+ static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
+ if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
+ grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) {
+ return grpc_static_slice_table[ent.idx];
+ }
+ }
+
+ interned_slice_refcount *s;
+ slice_shard *shard = &g_shards[SHARD_IDX(hash)];
+
+ gpr_mu_lock(&shard->mu);
+
+ /* search for an existing string */
+ size_t idx = TABLE_IDX(hash, shard->capacity);
+ for (s = shard->strs[idx]; s; s = s->bucket_next) {
+ if (s->hash == hash && grpc_slice_eq(slice, materialize(s))) {
+ if (gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) == 0) {
+ /* If we get here, we've added a ref to something that was about to
+ * die - drop it immediately.
+ * The *only* possible path here (given the shard mutex) should be to
+ * drop from one ref back to zero - assert that with a CAS */
+ GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0));
+ /* and treat this as if we were never here... sshhh */
+ } else {
+ gpr_mu_unlock(&shard->mu);
+ GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
+ return materialize(s);
+ }
+ }
+ }
+
+ /* not found: create a new string */
+ /* string data goes after the internal_string header */
+ s = gpr_malloc(sizeof(*s) + GRPC_SLICE_LENGTH(slice));
+ gpr_atm_rel_store(&s->refcnt, 1);
+ s->length = GRPC_SLICE_LENGTH(slice);
+ s->hash = hash;
+ s->base.vtable = &interned_slice_vtable;
+ s->base.sub_refcount = &s->sub;
+ s->sub.vtable = &interned_slice_sub_vtable;
+ s->sub.sub_refcount = &s->sub;
+ s->bucket_next = shard->strs[idx];
+ shard->strs[idx] = s;
+ memcpy(s + 1, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
+
+ shard->count++;
+
+ if (shard->count > shard->capacity * 2) {
+ grow_shard(shard);
+ }
+
+ gpr_mu_unlock(&shard->mu);
+
+ return materialize(s);
+}
+
+void grpc_test_only_set_slice_hash_seed(uint32_t seed) {
+ g_hash_seed = seed;
+ g_forced_hash_seed = 1;
+}
+
+void grpc_slice_intern_init(void) {
+ if (!g_forced_hash_seed) {
+ g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
+ }
+ for (size_t i = 0; i < SHARD_COUNT; i++) {
+ slice_shard *shard = &g_shards[i];
+ gpr_mu_init(&shard->mu);
+ shard->count = 0;
+ shard->capacity = INITIAL_SHARD_CAPACITY;
+ shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
+ memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
+ }
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(static_metadata_hash); i++) {
+ static_metadata_hash[i].hash = 0;
+ static_metadata_hash[i].idx = GRPC_STATIC_MDSTR_COUNT;
+ }
+ max_static_metadata_hash_probe = 0;
+ for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
+ static_metadata_hash_values[i] =
+ grpc_slice_default_hash_impl(grpc_static_slice_table[i]);
+ for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) {
+ size_t slot = (static_metadata_hash_values[i] + j) %
+ GPR_ARRAY_SIZE(static_metadata_hash);
+ if (static_metadata_hash[slot].idx == GRPC_STATIC_MDSTR_COUNT) {
+ static_metadata_hash[slot].hash = static_metadata_hash_values[i];
+ static_metadata_hash[slot].idx = (uint32_t)i;
+ if (j > max_static_metadata_hash_probe) {
+ max_static_metadata_hash_probe = (uint32_t)j;
+ }
+ break;
+ }
+ }
+ }
+}
+
+void grpc_slice_intern_shutdown(void) {
+ for (size_t i = 0; i < SHARD_COUNT; i++) {
+ slice_shard *shard = &g_shards[i];
+ gpr_mu_destroy(&shard->mu);
+ /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
+ if (shard->count != 0) {
+ gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
+ shard->count);
+ for (size_t j = 0; j < shard->capacity; j++) {
+ for (interned_slice_refcount *s = shard->strs[j]; s;
+ s = s->bucket_next) {
+ char *text =
+ grpc_dump_slice(materialize(s), GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_DEBUG, "LEAKED: %s", text);
+ gpr_free(text);
+ }
+ }
+ if (grpc_iomgr_abort_on_leaks()) {
+ abort();
+ }
+ }
+ gpr_free(shard->strs);
+ }
+}
diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h
index 6185333ca7..6467b0a8d6 100644
--- a/src/core/lib/slice/slice_internal.h
+++ b/src/core/lib/slice/slice_internal.h
@@ -46,4 +46,19 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx,
void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer *sb);
+/* Check if a slice is interned */
+bool grpc_slice_is_interned(grpc_slice slice);
+
+void grpc_slice_intern_init(void);
+void grpc_slice_intern_shutdown(void);
+void grpc_test_only_set_slice_hash_seed(uint32_t key);
+// if slice matches a static slice, returns the static slice
+// otherwise returns the passed in slice (without reffing it)
+// used for surface boundaries where we might receive an un-interned static
+// string
+grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
+ bool *returned_slice_is_different);
+uint32_t grpc_static_slice_hash(grpc_slice s);
+int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
+
#endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
diff --git a/src/core/lib/slice/slice_string_helpers.c b/src/core/lib/slice/slice_string_helpers.c
index 839c366b32..99695007cc 100644
--- a/src/core/lib/slice/slice_string_helpers.c
+++ b/src/core/lib/slice/slice_string_helpers.c
@@ -88,3 +88,8 @@ void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst) {
grpc_slice_buffer_add_indexed(dst, grpc_slice_ref_internal(str));
}
}
+
+bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result) {
+ return gpr_parse_bytes_to_uint32((const char *)GRPC_SLICE_START_PTR(str),
+ GRPC_SLICE_LENGTH(str), result) != 0;
+}
diff --git a/src/core/lib/slice/slice_string_helpers.h b/src/core/lib/slice/slice_string_helpers.h
index 151c720777..4a4deec6e5 100644
--- a/src/core/lib/slice/slice_string_helpers.h
+++ b/src/core/lib/slice/slice_string_helpers.h
@@ -34,12 +34,15 @@
#ifndef GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
#define GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
+#include <stdbool.h>
#include <stddef.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/port_platform.h>
+#include "src/core/lib/support/string.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -51,6 +54,8 @@ char *grpc_dump_slice(grpc_slice slice, uint32_t flags);
* should be a properly initialized instance. */
void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst);
+bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/core/lib/slice/slice_traits.h b/src/core/lib/slice/slice_traits.h
new file mode 100644
index 0000000000..8a283dc65c
--- /dev/null
+++ b/src/core/lib/slice/slice_traits.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H
+#define GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H
+
+#include <grpc/slice.h>
+#include <stdbool.h>
+
+bool grpc_slice_is_legal_header(grpc_slice s);
+bool grpc_slice_is_legal_nonbin_header(grpc_slice s);
+bool grpc_slice_is_bin_suffixed(grpc_slice s);
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H */
diff --git a/src/core/lib/support/log_posix.c b/src/core/lib/support/log_posix.c
index f972da0887..79458dd7a3 100644
--- a/src/core/lib/support/log_posix.c
+++ b/src/core/lib/support/log_posix.c
@@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <pthread.h>
#include <stdarg.h>
@@ -93,10 +94,13 @@ void gpr_default_log(gpr_log_func_args *args) {
strcpy(time_buffer, "error:strftime");
}
- fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n",
- gpr_log_severity_string(args->severity), time_buffer,
- (int)(now.tv_nsec), gettid(), display_file, args->line,
- args->message);
+ char *prefix;
+ gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
+ gpr_log_severity_string(args->severity), time_buffer,
+ (int)(now.tv_nsec), gettid(), display_file, args->line);
+
+ fprintf(stderr, "%-70s %s\n", prefix, args->message);
+ gpr_free(prefix);
}
#endif /* defined(GPR_POSIX_LOG) */
diff --git a/src/core/lib/support/time_windows.c b/src/core/lib/support/time_windows.c
index 6459732879..7b94a5b7bf 100644
--- a/src/core/lib/support/time_windows.c
+++ b/src/core/lib/support/time_windows.c
@@ -56,7 +56,7 @@ void gpr_time_init(void) {
g_time_scale = 1.0 / (double)frequency.QuadPart;
}
-gpr_timespec gpr_now(gpr_clock_type clock) {
+static gpr_timespec now_impl(gpr_clock_type clock) {
gpr_timespec now_tv;
LONGLONG diff;
struct _timeb now_tb;
@@ -84,6 +84,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
return now_tv;
}
+gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
+
+gpr_timespec gpr_now(gpr_clock_type clock_type) {
+ return gpr_now_impl(clock_type);
+}
+
void gpr_sleep_until(gpr_timespec until) {
gpr_timespec now;
gpr_timespec delta;
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index cac5737d91..70bab4c079 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -56,13 +56,15 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/validate_metadata.h"
+#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
- api:
+ api:
- initial metadata send
- message send
- status/close send (depending on client/server)
@@ -84,26 +86,32 @@ typedef enum {
/* Status came from 'the wire' - or somewhere below the surface
layer */
STATUS_FROM_WIRE,
- /* Status was created by some internal channel stack operation */
+ /* Status was created by some internal channel stack operation: must come via
+ add_batch_error */
STATUS_FROM_CORE,
+ /* Status was created by some surface error */
+ STATUS_FROM_SURFACE,
/* Status came from the server sending status */
STATUS_FROM_SERVER_STATUS,
STATUS_SOURCE_COUNT
} status_source;
typedef struct {
- uint8_t is_set;
- grpc_status_code code;
- grpc_mdstr *details;
+ bool is_set;
+ grpc_error *error;
} received_status;
+#define MAX_ERRORS_PER_BATCH 3
+
typedef struct batch_control {
grpc_call *call;
grpc_cq_completion cq_completion;
grpc_closure finish_batch;
void *notify_tag;
gpr_refcount steps_to_complete;
- grpc_error *error;
+
+ grpc_error *errors[MAX_ERRORS_PER_BATCH];
+ gpr_atm num_errors;
uint8_t send_initial_metadata;
uint8_t send_message;
@@ -185,6 +193,7 @@ struct grpc_call {
grpc_call *sibling_prev;
grpc_slice_buffer_stream sending_stream;
+
grpc_byte_stream *receiving_stream;
grpc_byte_buffer **receiving_buffer;
grpc_slice receiving_slice;
@@ -196,8 +205,7 @@ struct grpc_call {
union {
struct {
grpc_status_code *status;
- char **status_details;
- size_t *status_details_capacity;
+ grpc_slice *status_details;
} client;
struct {
int *cancelled;
@@ -207,6 +215,8 @@ struct grpc_call {
void *saved_receiving_stream_ready_bctlp;
};
+int grpc_call_error_trace = 0;
+
#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
#define CALL_ELEM_FROM_CALL(call, idx) \
@@ -216,21 +226,39 @@ struct grpc_call {
static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
grpc_transport_stream_op *op);
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_status_code status,
- const char *description);
-static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_status_code status,
- const char *description);
+static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ status_source source, grpc_status_code status,
+ const char *description);
+static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ status_source source, grpc_error *error);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
grpc_error *error);
static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error);
+static void get_final_status(grpc_call *call,
+ void (*set_value)(grpc_status_code code,
+ void *user_data),
+ void *set_value_user_data, grpc_slice *details);
+static void set_status_value_directly(grpc_status_code status, void *dest);
+static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ status_source source, grpc_error *error);
+static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl);
+static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl);
+static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
+ grpc_error *error);
+
+static void add_init_error(grpc_error **composite, grpc_error *new) {
+ if (new == GRPC_ERROR_NONE) return;
+ if (*composite == GRPC_ERROR_NONE)
+ *composite = GRPC_ERROR_CREATE("Call creation failed");
+ *composite = grpc_error_add_child(*composite, new);
+}
grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
const grpc_call_create_args *args,
grpc_call **out_call) {
size_t i, j;
+ grpc_error *error = GRPC_ERROR_NONE;
grpc_channel_stack *channel_stack =
grpc_channel_get_channel_stack(args->channel);
grpc_call *call;
@@ -246,14 +274,16 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
- grpc_mdstr *path = NULL;
+ grpc_slice path = grpc_empty_slice();
if (call->is_client) {
GPR_ASSERT(args->add_initial_metadata_count <
MAX_SEND_EXTRA_METADATA_COUNT);
for (i = 0; i < args->add_initial_metadata_count; i++) {
call->send_extra_metadata[i].md = args->add_initial_metadata[i];
- if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) {
- path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value);
+ if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]),
+ GRPC_MDSTR_PATH)) {
+ path = grpc_slice_ref_internal(
+ GRPC_MDVALUE(args->add_initial_metadata[i]));
}
}
call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
@@ -287,12 +317,18 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
/* TODO(ctiller): This should change to use the appropriate census start_op
* call. */
if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
- GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+ if (0 == (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)) {
+ add_init_error(&error,
+ GRPC_ERROR_CREATE("Census tracing propagation requested "
+ "without Census context propagation"));
+ }
grpc_call_context_set(
call, GRPC_CONTEXT_TRACING,
args->parent_call->context[GRPC_CONTEXT_TRACING].value, NULL);
- } else {
- GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+ } else if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT) {
+ add_init_error(&error,
+ GRPC_ERROR_CREATE("Census context propagation requested "
+ "without Census tracing propagation"));
}
if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
call->cancellation_is_inherited = 1;
@@ -315,15 +351,14 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
/* initial refcount dropped by grpc_call_destroy */
- grpc_error *error = grpc_call_stack_init(
- exec_ctx, channel_stack, 1, destroy_call, call, call->context,
- args->server_transport_data, path, call->start_time, send_deadline,
- CALL_STACK_FROM_CALL(call));
+ add_init_error(&error, grpc_call_stack_init(exec_ctx, channel_stack, 1,
+ destroy_call, call, call->context,
+ args->server_transport_data, path,
+ call->start_time, send_deadline,
+ CALL_STACK_FROM_CALL(call)));
if (error != GRPC_ERROR_NONE) {
- grpc_status_code status;
- const char *error_str;
- grpc_error_get_status(error, &status, &error_str);
- close_with_status(exec_ctx, call, status, error_str);
+ cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
+ GRPC_ERROR_REF(error));
}
if (args->cq != NULL) {
GPR_ASSERT(
@@ -342,7 +377,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
- if (path != NULL) GRPC_MDSTR_UNREF(exec_ctx, path);
+ grpc_slice_unref_internal(exec_ctx, path);
GPR_TIMER_END("grpc_call_create", 0);
return error;
@@ -377,24 +412,6 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
}
-static void get_final_status(grpc_call *call,
- void (*set_value)(grpc_status_code code,
- void *user_data),
- void *set_value_user_data) {
- int i;
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (call->status[i].is_set) {
- set_value(call->status[i].code, set_value_user_data);
- return;
- }
- }
- if (call->is_client) {
- set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
- } else {
- set_value(GRPC_STATUS_OK, set_value_user_data);
- }
-}
-
static void set_status_value_directly(grpc_status_code status, void *dest);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) {
@@ -410,11 +427,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
gpr_mu_destroy(&c->mu);
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (c->status[i].details) {
- GRPC_MDSTR_UNREF(exec_ctx, c->status[i].details);
- }
- }
for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
}
@@ -428,42 +440,253 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
}
grpc_channel *channel = c->channel;
- get_final_status(call, set_status_value_directly,
- &c->final_info.final_status);
+ get_final_status(call, set_status_value_directly, &c->final_info.final_status,
+ NULL);
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ GRPC_ERROR_UNREF(c->status[i].error);
+ }
+
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
GPR_TIMER_END("destroy_call", 0);
}
-static void set_status_code(grpc_call *call, status_source source,
- uint32_t status) {
- if (call->status[source].is_set) return;
+void grpc_call_destroy(grpc_call *c) {
+ int cancel;
+ grpc_call *parent = c->parent;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ GPR_TIMER_BEGIN("grpc_call_destroy", 0);
+ GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
+
+ if (parent) {
+ gpr_mu_lock(&parent->mu);
+ if (c == parent->first_child) {
+ parent->first_child = c->sibling_next;
+ if (c == parent->first_child) {
+ parent->first_child = NULL;
+ }
+ c->sibling_prev->sibling_next = c->sibling_next;
+ c->sibling_next->sibling_prev = c->sibling_prev;
+ }
+ gpr_mu_unlock(&parent->mu);
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
+ }
+
+ gpr_mu_lock(&c->mu);
+ GPR_ASSERT(!c->destroy_called);
+ c->destroy_called = 1;
+ cancel = !c->received_final_op;
+ gpr_mu_unlock(&c->mu);
+ if (cancel) grpc_call_cancel(c, NULL);
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_TIMER_END("grpc_call_destroy", 0);
+}
+
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
+ GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
+ GPR_ASSERT(!reserved);
+ return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
+ NULL);
+}
+
+static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ grpc_transport_stream_op *op) {
+ grpc_call_element *elem;
+
+ GPR_TIMER_BEGIN("execute_op", 0);
+ elem = CALL_ELEM_FROM_CALL(call, 0);
+ op->context = call->context;
+ elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+ GPR_TIMER_END("execute_op", 0);
+}
+
+char *grpc_call_get_peer(grpc_call *call) {
+ grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ char *result;
+ GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
+ result = elem->filter->get_peer(&exec_ctx, elem);
+ if (result == NULL) {
+ result = grpc_channel_get_target(call->channel);
+ }
+ if (result == NULL) {
+ result = gpr_strdup("unknown");
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ return result;
+}
+
+grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
+ return CALL_FROM_TOP_ELEM(elem);
+}
+
+/*******************************************************************************
+ * CANCELLATION
+ */
+
+grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
+ grpc_status_code status,
+ const char *description,
+ void *reserved) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_API_TRACE(
+ "grpc_call_cancel_with_status("
+ "c=%p, status=%d, description=%s, reserved=%p)",
+ 4, (c, (int)status, description, reserved));
+ GPR_ASSERT(reserved == NULL);
+ gpr_mu_lock(&c->mu);
+ cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status,
+ description);
+ gpr_mu_unlock(&c->mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return GRPC_CALL_OK;
+}
+
+typedef struct termination_closure {
+ grpc_closure closure;
+ grpc_call *call;
+ grpc_transport_stream_op op;
+} termination_closure;
+
+static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
+ grpc_error *error) {
+ termination_closure *tc = tcp;
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "termination");
+ gpr_free(tc);
+}
+
+static void send_termination(grpc_exec_ctx *exec_ctx, void *tcp,
+ grpc_error *error) {
+ termination_closure *tc = tcp;
+ memset(&tc->op, 0, sizeof(tc->op));
+ tc->op.cancel_error = GRPC_ERROR_REF(error);
+ /* reuse closure to catch completion */
+ tc->op.on_complete = grpc_closure_init(&tc->closure, done_termination, tc,
+ grpc_schedule_on_exec_ctx);
+ execute_op(exec_ctx, tc->call, &tc->op);
+}
+
+static void terminate_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_error *error) {
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(*tc));
+ tc->call = c;
+ GRPC_CALL_INTERNAL_REF(tc->call, "termination");
+ grpc_closure_sched(exec_ctx, grpc_closure_init(&tc->closure, send_termination,
+ tc, grpc_schedule_on_exec_ctx),
+ error);
+}
+
+static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ status_source source, grpc_error *error) {
+ set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
+ terminate_with_error(exec_ctx, c, error);
+}
+
+static grpc_error *error_from_status(grpc_status_code status,
+ const char *description) {
+ return grpc_error_set_int(
+ grpc_error_set_str(GRPC_ERROR_CREATE(description),
+ GRPC_ERROR_STR_GRPC_MESSAGE, description),
+ GRPC_ERROR_INT_GRPC_STATUS, status);
+}
- call->status[source].is_set = 1;
- call->status[source].code = (grpc_status_code)status;
+static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ status_source source, grpc_status_code status,
+ const char *description) {
+ cancel_with_error(exec_ctx, c, source,
+ error_from_status(status, description));
}
-static void set_status_details(grpc_exec_ctx *exec_ctx, grpc_call *call,
- status_source source, grpc_mdstr *status) {
- if (call->status[source].details != NULL) {
- GRPC_MDSTR_UNREF(exec_ctx, status);
+/*******************************************************************************
+ * FINAL STATUS CODE MANIPULATION
+ */
+
+static bool get_final_status_from(
+ grpc_call *call, status_source from_source, bool allow_ok_status,
+ void (*set_value)(grpc_status_code code, void *user_data),
+ void *set_value_user_data, grpc_slice *details) {
+ grpc_status_code code;
+ const char *msg = NULL;
+ grpc_error_get_status(call->status[from_source].error, call->send_deadline,
+ &code, &msg, NULL);
+ if (code == GRPC_STATUS_OK && !allow_ok_status) {
+ return false;
+ }
+
+ set_value(code, set_value_user_data);
+ if (details != NULL) {
+ *details =
+ msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg);
+ }
+ return true;
+}
+
+static void get_final_status(grpc_call *call,
+ void (*set_value)(grpc_status_code code,
+ void *user_data),
+ void *set_value_user_data, grpc_slice *details) {
+ int i;
+ if (grpc_call_error_trace) {
+ gpr_log(GPR_DEBUG, "get_final_status %s", call->is_client ? "CLI" : "SVR");
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (call->status[i].is_set) {
+ gpr_log(GPR_DEBUG, " %d: %s", i,
+ grpc_error_string(call->status[i].error));
+ }
+ }
+ }
+ /* first search through ignoring "OK" statuses: if something went wrong,
+ * ensure we report it */
+ for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) {
+ /* search for the best status we can present: ideally the error we use has a
+ clearly defined grpc-status, and we'll prefer that. */
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (call->status[i].is_set &&
+ grpc_error_has_clear_grpc_status(call->status[i].error)) {
+ if (get_final_status_from(call, (status_source)i, allow_ok_status != 0,
+ set_value, set_value_user_data, details)) {
+ return;
+ }
+ }
+ }
+ /* If no clearly defined status exists, search for 'anything' */
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (call->status[i].is_set) {
+ if (get_final_status_from(call, (status_source)i, allow_ok_status != 0,
+ set_value, set_value_user_data, details)) {
+ return;
+ }
+ }
+ }
+ }
+ /* If nothing exists, set some default */
+ if (call->is_client) {
+ set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
} else {
- call->status[source].details = status;
+ set_value(GRPC_STATUS_OK, set_value_user_data);
}
}
static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
status_source source, grpc_error *error) {
- grpc_status_code status;
- const char *msg;
- grpc_error_get_status(error, &status, &msg);
- set_status_code(call, source, (uint32_t)status);
- set_status_details(exec_ctx, call, source, grpc_mdstr_from_string(msg));
+ if (call->status[source].is_set) {
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ call->status[source].is_set = true;
+ call->status[source].error = error;
}
+/*******************************************************************************
+ * COMPRESSION
+ */
+
static void set_incoming_compression_algorithm(
grpc_call *call, grpc_compression_algorithm algo) {
GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
@@ -496,7 +719,7 @@ uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
static void destroy_encodings_accepted_by_peer(void *p) { return; }
static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
- grpc_call *call, grpc_mdelem *mdel) {
+ grpc_call *call, grpc_mdelem mdel) {
size_t i;
grpc_compression_algorithm algorithm;
grpc_slice_buffer accept_encoding_parts;
@@ -511,7 +734,7 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
return;
}
- accept_encoding_slice = mdel->value->slice;
+ accept_encoding_slice = GRPC_MDVALUE(mdel);
grpc_slice_buffer_init(&accept_encoding_parts);
grpc_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
@@ -520,15 +743,13 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
for (i = 0; i < accept_encoding_parts.count; i++) {
- const grpc_slice *accept_encoding_entry_slice =
- &accept_encoding_parts.slices[i];
- if (grpc_compression_algorithm_parse(
- (const char *)GRPC_SLICE_START_PTR(*accept_encoding_entry_slice),
- GRPC_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
+ grpc_slice accept_encoding_entry_slice = accept_encoding_parts.slices[i];
+ if (grpc_compression_algorithm_parse(accept_encoding_entry_slice,
+ &algorithm)) {
GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
} else {
char *accept_encoding_entry_str =
- grpc_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
+ grpc_slice_to_c_string(accept_encoding_entry_slice);
gpr_log(GPR_ERROR,
"Invalid entry in accept encoding metadata: '%s'. Ignoring.",
accept_encoding_entry_str);
@@ -551,36 +772,6 @@ uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
return encodings_accepted_by_peer;
}
-static void get_final_details(grpc_call *call, char **out_details,
- size_t *out_details_capacity) {
- int i;
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (call->status[i].is_set) {
- if (call->status[i].details) {
- grpc_slice details = call->status[i].details->slice;
- size_t len = GRPC_SLICE_LENGTH(details);
- if (len + 1 > *out_details_capacity) {
- *out_details_capacity =
- GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
- *out_details = gpr_realloc(*out_details, *out_details_capacity);
- }
- memcpy(*out_details, GRPC_SLICE_START_PTR(details), len);
- (*out_details)[len] = 0;
- } else {
- goto no_details;
- }
- return;
- }
- }
-
-no_details:
- if (0 == *out_details_capacity) {
- *out_details_capacity = 8;
- *out_details = gpr_malloc(*out_details_capacity);
- }
- **out_details = 0;
-}
-
static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
return (grpc_linked_mdelem *)&md->internal_data;
}
@@ -607,24 +798,19 @@ static int prepare_application_metadata(
get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
- l->md = grpc_mdelem_from_string_and_buffer(
- exec_ctx, md->key, (const uint8_t *)md->value, md->value_length);
- if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
- GRPC_MDSTR_LENGTH(l->md->key))) {
- gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
- grpc_mdstr_as_c_string(l->md->key));
+ if (!GRPC_LOG_IF_ERROR("validate_metadata",
+ grpc_validate_header_key_is_legal(md->key))) {
break;
- } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key),
- GRPC_MDSTR_LENGTH(l->md->key)) &&
- !grpc_header_nonbin_value_is_legal(
- grpc_mdstr_as_c_string(l->md->value),
- GRPC_MDSTR_LENGTH(l->md->value))) {
- gpr_log(GPR_ERROR, "attempt to send invalid metadata value");
+ } else if (!grpc_is_binary_header(md->key) &&
+ !GRPC_LOG_IF_ERROR(
+ "validate_metadata",
+ grpc_validate_header_nonbin_value_is_legal(md->value))) {
break;
}
+ l->md = grpc_mdelem_from_grpc_metadata(exec_ctx, (grpc_metadata *)md);
}
if (i != total_count) {
- for (int j = 0; j <= i; j++) {
+ for (int j = 0; j < i; j++) {
const grpc_metadata *md =
get_md_elem(metadata, additional_metadata, j, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
@@ -636,278 +822,41 @@ static int prepare_application_metadata(
if (call->send_extra_metadata_count == 0) {
prepend_extra_metadata = 0;
} else {
- for (i = 1; i < call->send_extra_metadata_count; i++) {
- call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
- }
- for (i = 0; i < call->send_extra_metadata_count - 1; i++) {
- call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1];
+ for (i = 0; i < call->send_extra_metadata_count; i++) {
+ GRPC_LOG_IF_ERROR("prepare_application_metadata",
+ grpc_metadata_batch_link_tail(
+ exec_ctx, batch, &call->send_extra_metadata[i]));
}
}
}
- for (i = 1; i < total_count; i++) {
- grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
- grpc_metadata *prev_md =
- get_md_elem(metadata, additional_metadata, i - 1, count);
- linked_from_md(md)->prev = linked_from_md(prev_md);
- }
- for (i = 0; i < total_count - 1; i++) {
+ for (i = 0; i < total_count; i++) {
grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
- grpc_metadata *next_md =
- get_md_elem(metadata, additional_metadata, i + 1, count);
- linked_from_md(md)->next = linked_from_md(next_md);
- }
-
- switch (prepend_extra_metadata * 2 + (total_count != 0)) {
- case 0:
- /* no prepend, no metadata => nothing to do */
- batch->list.head = batch->list.tail = NULL;
- break;
- case 1: {
- /* metadata, but no prepend */
- grpc_metadata *first_md =
- get_md_elem(metadata, additional_metadata, 0, count);
- grpc_metadata *last_md =
- get_md_elem(metadata, additional_metadata, total_count - 1, count);
- batch->list.head = linked_from_md(first_md);
- batch->list.tail = linked_from_md(last_md);
- batch->list.head->prev = NULL;
- batch->list.tail->next = NULL;
- break;
- }
- case 2:
- /* prepend, but no md */
- batch->list.head = &call->send_extra_metadata[0];
- batch->list.tail =
- &call->send_extra_metadata[call->send_extra_metadata_count - 1];
- batch->list.head->prev = NULL;
- batch->list.tail->next = NULL;
- call->send_extra_metadata_count = 0;
- break;
- case 3: {
- /* prepend AND md */
- grpc_metadata *first_md =
- get_md_elem(metadata, additional_metadata, 0, count);
- grpc_metadata *last_md =
- get_md_elem(metadata, additional_metadata, total_count - 1, count);
- batch->list.head = &call->send_extra_metadata[0];
- call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
- linked_from_md(first_md);
- linked_from_md(first_md)->prev =
- &call->send_extra_metadata[call->send_extra_metadata_count - 1];
- batch->list.tail = linked_from_md(last_md);
- batch->list.head->prev = NULL;
- batch->list.tail->next = NULL;
- call->send_extra_metadata_count = 0;
- break;
- }
- default:
- GPR_UNREACHABLE_CODE(return 0);
+ GRPC_LOG_IF_ERROR(
+ "prepare_application_metadata",
+ grpc_metadata_batch_link_tail(exec_ctx, batch, linked_from_md(md)));
}
+ call->send_extra_metadata_count = 0;
return 1;
}
-void grpc_call_destroy(grpc_call *c) {
- int cancel;
- grpc_call *parent = c->parent;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- GPR_TIMER_BEGIN("grpc_call_destroy", 0);
- GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
-
- if (parent) {
- gpr_mu_lock(&parent->mu);
- if (c == parent->first_child) {
- parent->first_child = c->sibling_next;
- if (c == parent->first_child) {
- parent->first_child = NULL;
- }
- c->sibling_prev->sibling_next = c->sibling_next;
- c->sibling_next->sibling_prev = c->sibling_prev;
- }
- gpr_mu_unlock(&parent->mu);
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
- }
-
- gpr_mu_lock(&c->mu);
- GPR_ASSERT(!c->destroy_called);
- c->destroy_called = 1;
- cancel = !c->received_final_op;
- gpr_mu_unlock(&c->mu);
- if (cancel) grpc_call_cancel(c, NULL);
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
- grpc_exec_ctx_finish(&exec_ctx);
- GPR_TIMER_END("grpc_call_destroy", 0);
-}
-
-grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
- GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
- GPR_ASSERT(!reserved);
- return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
- NULL);
-}
-
-grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
- grpc_status_code status,
- const char *description,
- void *reserved) {
- grpc_call_error r;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- GRPC_API_TRACE(
- "grpc_call_cancel_with_status("
- "c=%p, status=%d, description=%s, reserved=%p)",
- 4, (c, (int)status, description, reserved));
- GPR_ASSERT(reserved == NULL);
- gpr_mu_lock(&c->mu);
- r = cancel_with_status(&exec_ctx, c, status, description);
- gpr_mu_unlock(&c->mu);
- grpc_exec_ctx_finish(&exec_ctx);
- return r;
-}
-
-typedef struct termination_closure {
- grpc_closure closure;
- grpc_call *call;
- grpc_error *error;
- enum { TC_CANCEL, TC_CLOSE } type;
- grpc_transport_stream_op op;
-} termination_closure;
-
-static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
- grpc_error *error) {
- termination_closure *tc = tcp;
- switch (tc->type) {
- case TC_CANCEL:
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
- break;
- case TC_CLOSE:
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
- break;
- }
- GRPC_ERROR_UNREF(tc->error);
- gpr_free(tc);
-}
-
-static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
- termination_closure *tc = tcp;
- memset(&tc->op, 0, sizeof(tc->op));
- tc->op.cancel_error = tc->error;
- /* reuse closure to catch completion */
- grpc_closure_init(&tc->closure, done_termination, tc,
- grpc_schedule_on_exec_ctx);
- tc->op.on_complete = &tc->closure;
- execute_op(exec_ctx, tc->call, &tc->op);
-}
-
-static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
- termination_closure *tc = tcp;
- memset(&tc->op, 0, sizeof(tc->op));
- tc->op.close_error = tc->error;
- /* reuse closure to catch completion */
- grpc_closure_init(&tc->closure, done_termination, tc,
- grpc_schedule_on_exec_ctx);
- tc->op.on_complete = &tc->closure;
- execute_op(exec_ctx, tc->call, &tc->op);
-}
-
-static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
- termination_closure *tc) {
- set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
- tc->error);
-
- if (tc->type == TC_CANCEL) {
- grpc_closure_init(&tc->closure, send_cancel, tc, grpc_schedule_on_exec_ctx);
- GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
- } else if (tc->type == TC_CLOSE) {
- grpc_closure_init(&tc->closure, send_close, tc, grpc_schedule_on_exec_ctx);
- GRPC_CALL_INTERNAL_REF(tc->call, "close");
- }
- grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
- return GRPC_CALL_OK;
-}
-
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_status_code status,
- const char *description) {
- GPR_ASSERT(status != GRPC_STATUS_OK);
- termination_closure *tc = gpr_malloc(sizeof(*tc));
- memset(tc, 0, sizeof(termination_closure));
- tc->type = TC_CANCEL;
- tc->call = c;
- tc->error = grpc_error_set_int(
- grpc_error_set_str(GRPC_ERROR_CREATE(description),
- GRPC_ERROR_STR_GRPC_MESSAGE, description),
- GRPC_ERROR_INT_GRPC_STATUS, status);
-
- return terminate_with_status(exec_ctx, tc);
-}
-
-static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_status_code status,
- const char *description) {
- GPR_ASSERT(status != GRPC_STATUS_OK);
- termination_closure *tc = gpr_malloc(sizeof(*tc));
- memset(tc, 0, sizeof(termination_closure));
- tc->type = TC_CLOSE;
- tc->call = c;
- tc->error = grpc_error_set_int(
- grpc_error_set_str(GRPC_ERROR_CREATE(description),
- GRPC_ERROR_STR_GRPC_MESSAGE, description),
- GRPC_ERROR_INT_GRPC_STATUS, status);
-
- return terminate_with_status(exec_ctx, tc);
-}
-
-static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_transport_stream_op *op) {
- grpc_call_element *elem;
-
- GPR_TIMER_BEGIN("execute_op", 0);
- elem = CALL_ELEM_FROM_CALL(call, 0);
- op->context = call->context;
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
- GPR_TIMER_END("execute_op", 0);
-}
-
-char *grpc_call_get_peer(grpc_call *call) {
- grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- char *result;
- GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
- result = elem->filter->get_peer(&exec_ctx, elem);
- if (result == NULL) {
- result = grpc_channel_get_target(call->channel);
- }
- if (result == NULL) {
- result = gpr_strdup("unknown");
- }
- grpc_exec_ctx_finish(&exec_ctx);
- return result;
-}
-
-grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
- return CALL_FROM_TOP_ELEM(elem);
-}
-
/* we offset status by a small amount when storing it into transport metadata
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
*/
#define STATUS_OFFSET 1
static void destroy_status(void *ignored) {}
-static uint32_t decode_status(grpc_mdelem *md) {
+static uint32_t decode_status(grpc_mdelem md) {
uint32_t status;
void *user_data;
- if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
- if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
- if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data != NULL) {
status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
} else {
- if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
- GRPC_SLICE_LENGTH(md->value->slice),
- &status)) {
+ if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
}
grpc_mdelem_set_user_data(md, destroy_status,
@@ -916,93 +865,104 @@ static uint32_t decode_status(grpc_mdelem *md) {
return status;
}
-static grpc_compression_algorithm decode_compression(grpc_mdelem *md) {
+static grpc_compression_algorithm decode_compression(grpc_mdelem md) {
grpc_compression_algorithm algorithm =
- grpc_compression_algorithm_from_mdstr(md->value);
+ grpc_compression_algorithm_from_slice(GRPC_MDVALUE(md));
if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
- const char *md_c_str = grpc_mdstr_as_c_string(md->value);
+ char *md_c_str = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR,
"Invalid incoming compression algorithm: '%s'. Interpreting "
"incoming data as uncompressed.",
md_c_str);
+ gpr_free(md_c_str);
return GRPC_COMPRESS_NONE;
}
return algorithm;
}
-static grpc_mdelem *recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_mdelem *elem) {
- if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
- GPR_TIMER_BEGIN("status", 0);
- set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
- GPR_TIMER_END("status", 0);
- return NULL;
- } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
- GPR_TIMER_BEGIN("status-details", 0);
- set_status_details(exec_ctx, call, STATUS_FROM_WIRE,
- GRPC_MDSTR_REF(elem->value));
- GPR_TIMER_END("status-details", 0);
- return NULL;
- }
- return elem;
+static void recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ grpc_metadata_batch *b) {
+ if (b->idx.named.grpc_status != NULL) {
+ uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
+ grpc_error *error =
+ status_code == GRPC_STATUS_OK
+ ? GRPC_ERROR_NONE
+ : grpc_error_set_int(GRPC_ERROR_CREATE("Error received from peer"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ (intptr_t)status_code);
+
+ if (b->idx.named.grpc_message != NULL) {
+ char *msg =
+ grpc_slice_to_c_string(GRPC_MDVALUE(b->idx.named.grpc_message->md));
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
+ gpr_free(msg);
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_message);
+ } else {
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, "");
+ }
+
+ set_status_from_error(exec_ctx, call, STATUS_FROM_WIRE, error);
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_status);
+ }
}
-static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
- int is_trailing) {
+static void publish_app_metadata(grpc_call *call, grpc_metadata_batch *b,
+ int is_trailing) {
+ if (b->list.count == 0) return;
+ GPR_TIMER_BEGIN("publish_app_metadata", 0);
grpc_metadata_array *dest;
grpc_metadata *mdusr;
- GPR_TIMER_BEGIN("publish_app_metadata", 0);
dest = call->buffered_metadata[is_trailing];
- if (dest->count == dest->capacity) {
- dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
+ if (dest->count + b->list.count > dest->capacity) {
+ dest->capacity =
+ GPR_MAX(dest->capacity + b->list.count, dest->capacity * 3 / 2);
dest->metadata =
gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
}
- mdusr = &dest->metadata[dest->count++];
- mdusr->key = grpc_mdstr_as_c_string(elem->key);
- mdusr->value = grpc_mdstr_as_c_string(elem->value);
- mdusr->value_length = GRPC_SLICE_LENGTH(elem->value->slice);
+ for (grpc_linked_mdelem *l = b->list.head; l != NULL; l = l->next) {
+ mdusr = &dest->metadata[dest->count++];
+ /* we pass back borrowed slices that are valid whilst the call is valid */
+ mdusr->key = GRPC_MDKEY(l->md);
+ mdusr->value = GRPC_MDVALUE(l->md);
+ }
GPR_TIMER_END("publish_app_metadata", 0);
- return elem;
}
-static grpc_mdelem *recv_initial_filter(grpc_exec_ctx *exec_ctx, void *args,
- grpc_mdelem *elem) {
- grpc_call *call = args;
- elem = recv_common_filter(exec_ctx, call, elem);
- if (elem == NULL) {
- return NULL;
- } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
+static void recv_initial_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ grpc_metadata_batch *b) {
+ recv_common_filter(exec_ctx, call, b);
+
+ if (b->idx.named.grpc_encoding != NULL) {
GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
- set_incoming_compression_algorithm(call, decode_compression(elem));
+ set_incoming_compression_algorithm(
+ call, decode_compression(b->idx.named.grpc_encoding->md));
GPR_TIMER_END("incoming_compression_algorithm", 0);
- return NULL;
- } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_encoding);
+ }
+
+ if (b->idx.named.grpc_accept_encoding != NULL) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
- set_encodings_accepted_by_peer(exec_ctx, call, elem);
+ set_encodings_accepted_by_peer(exec_ctx, call,
+ b->idx.named.grpc_accept_encoding->md);
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_accept_encoding);
GPR_TIMER_END("encodings_accepted_by_peer", 0);
- return NULL;
- } else {
- return publish_app_metadata(call, elem, 0);
}
+
+ publish_app_metadata(call, b, false);
}
-static grpc_mdelem *recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
- grpc_mdelem *elem) {
+static void recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
+ grpc_metadata_batch *b) {
grpc_call *call = args;
- elem = recv_common_filter(exec_ctx, call, elem);
- if (elem == NULL) {
- return NULL;
- } else {
- return publish_app_metadata(call, elem, 1);
- }
+ recv_common_filter(exec_ctx, call, b);
+ publish_app_metadata(call, b, true);
}
grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
return CALL_STACK_FROM_CALL(call);
}
-/*
+/*******************************************************************************
* BATCH API IMPLEMENTATION
*/
@@ -1053,14 +1013,83 @@ static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
}
+static grpc_error *consolidate_batch_errors(batch_control *bctl) {
+ size_t n = (size_t)gpr_atm_no_barrier_load(&bctl->num_errors);
+ if (n == 0) {
+ return GRPC_ERROR_NONE;
+ } else if (n == 1) {
+ /* Skip creating a composite error in the case that only one error was
+ logged */
+ grpc_error *e = bctl->errors[0];
+ bctl->errors[0] = NULL;
+ return e;
+ } else {
+ grpc_error *error =
+ GRPC_ERROR_CREATE_REFERENCING("Call batch failed", bctl->errors, n);
+ for (size_t i = 0; i < n; i++) {
+ GRPC_ERROR_UNREF(bctl->errors[i]);
+ bctl->errors[i] = NULL;
+ }
+ return error;
+ }
+}
+
static void post_batch_completion(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
+ grpc_call *child_call;
+ grpc_call *next_child_call;
grpc_call *call = bctl->call;
- grpc_error *error = bctl->error;
+ grpc_error *error = consolidate_batch_errors(bctl);
+
+ gpr_mu_lock(&call->mu);
+
+ if (bctl->send_initial_metadata) {
+ grpc_metadata_batch_destroy(
+ exec_ctx,
+ &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
+ }
+ if (bctl->send_message) {
+ call->sending_message = false;
+ }
+ if (bctl->send_final_op) {
+ grpc_metadata_batch_destroy(
+ exec_ctx,
+ &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
+ }
if (bctl->recv_final_op) {
+ grpc_metadata_batch *md =
+ &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
+ recv_trailing_filter(exec_ctx, call, md);
+
+ call->received_final_op = true;
+ /* propagate cancellation to any interested children */
+ child_call = call->first_child;
+ if (child_call != NULL) {
+ do {
+ next_child_call = child_call->sibling_next;
+ if (child_call->cancellation_is_inherited) {
+ GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
+ grpc_call_cancel(child_call, NULL);
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
+ }
+ child_call = next_child_call;
+ } while (child_call != call->first_child);
+ }
+
+ if (call->is_client) {
+ get_final_status(call, set_status_value_directly,
+ call->final_op.client.status,
+ call->final_op.client.status_details);
+ } else {
+ get_final_status(call, set_cancelled_value,
+ call->final_op.server.cancelled, NULL);
+ }
+
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
}
+ gpr_mu_unlock(&call->mu);
+
if (bctl->is_notify_tag_closure) {
/* unrefs bctl->error */
grpc_closure_run(exec_ctx, bctl->notify_tag, error);
@@ -1077,6 +1106,12 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
}
}
+static void finish_batch_step(grpc_exec_ctx *exec_ctx, batch_control *bctl) {
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
+}
+
static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
grpc_call *call = bctl->call;
@@ -1087,9 +1122,7 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
call->receiving_message = 0;
grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
call->receiving_stream = NULL;
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
+ finish_batch_step(exec_ctx, bctl);
return;
}
if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
@@ -1120,9 +1153,7 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
call->receiving_stream = NULL;
grpc_byte_buffer_destroy(*call->receiving_buffer);
*call->receiving_buffer = NULL;
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
+ finish_batch_step(exec_ctx, bctl);
}
}
@@ -1132,9 +1163,7 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx,
if (call->receiving_stream == NULL) {
*call->receiving_buffer = NULL;
call->receiving_message = 0;
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
+ finish_batch_step(exec_ctx, bctl);
} else {
call->test_only_last_message_flags = call->receiving_stream->flags;
if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
@@ -1154,14 +1183,12 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
+ gpr_mu_lock(&bctl->call->mu);
if (error != GRPC_ERROR_NONE) {
- grpc_status_code status;
- const char *msg;
- grpc_error_get_status(error, &status, &msg);
- close_with_status(exec_ctx, call, status, msg);
+ cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
+ GRPC_ERROR_REF(error));
}
- gpr_mu_lock(&bctl->call->mu);
- if (bctl->call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
+ if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
call->receiving_stream == NULL) {
gpr_mu_unlock(&bctl->call->mu);
process_data_after_md(exec_ctx, bctlp);
@@ -1186,7 +1213,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
algo);
gpr_log(GPR_ERROR, "%s", error_msg);
- close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
+ GRPC_STATUS_UNIMPLEMENTED, error_msg);
} else if (grpc_compression_options_is_algorithm_enabled(
&compression_options, algo) == 0) {
/* check if algorithm is supported by current channel config */
@@ -1195,7 +1223,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
algo_name);
gpr_log(GPR_ERROR, "%s", error_msg);
- close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
+ GRPC_STATUS_UNIMPLEMENTED, error_msg);
} else {
call->incoming_compression_algorithm = algo;
}
@@ -1221,12 +1250,15 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
}
}
-static void add_batch_error(batch_control *bctl, grpc_error *error) {
+static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
+ grpc_error *error) {
if (error == GRPC_ERROR_NONE) return;
- if (bctl->error == GRPC_ERROR_NONE) {
- bctl->error = GRPC_ERROR_CREATE("Call batch operation failed");
+ int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
+ if (idx == 0) {
+ cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE,
+ GRPC_ERROR_REF(error));
}
- bctl->error = grpc_error_add_child(bctl->error, error);
+ bctl->errors[idx] = error;
}
static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
@@ -1236,12 +1268,13 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&call->mu);
- add_batch_error(bctl, GRPC_ERROR_REF(error));
+ add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error));
if (error == GRPC_ERROR_NONE) {
grpc_metadata_batch *md =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
- grpc_metadata_batch_filter(exec_ctx, md, recv_initial_filter, call);
+ recv_initial_filter(exec_ctx, call, md);
+ /* TODO(ctiller): this could be moved into recv_initial_filter now */
GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
validate_filtered_metadata(exec_ctx, bctl);
GPR_TIMER_END("validate_filtered_metadata", 0);
@@ -1260,90 +1293,20 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
receiving_stream_ready, call->saved_receiving_stream_ready_bctlp,
grpc_schedule_on_exec_ctx);
call->saved_receiving_stream_ready_bctlp = NULL;
- grpc_closure_sched(exec_ctx, saved_rsr_closure, error);
+ grpc_closure_sched(exec_ctx, saved_rsr_closure, GRPC_ERROR_REF(error));
}
gpr_mu_unlock(&call->mu);
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
+ finish_batch_step(exec_ctx, bctl);
}
static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error) {
batch_control *bctl = bctlp;
- grpc_call *call = bctl->call;
- grpc_call *child_call;
- grpc_call *next_child_call;
-
- GRPC_ERROR_REF(error);
-
- gpr_mu_lock(&call->mu);
-
- // If the error has an associated status code, set the call's status.
- intptr_t status;
- if (error != GRPC_ERROR_NONE &&
- grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
- set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
- }
-
- if (bctl->send_initial_metadata) {
- if (error != GRPC_ERROR_NONE) {
- set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
- }
- grpc_metadata_batch_destroy(
- exec_ctx,
- &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
- }
- if (bctl->send_message) {
- call->sending_message = 0;
- }
- if (bctl->send_final_op) {
- grpc_metadata_batch_destroy(
- exec_ctx,
- &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
- }
- if (bctl->recv_final_op) {
- grpc_metadata_batch *md =
- &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- grpc_metadata_batch_filter(exec_ctx, md, recv_trailing_filter, call);
- call->received_final_op = true;
- /* propagate cancellation to any interested children */
- child_call = call->first_child;
- if (child_call != NULL) {
- do {
- next_child_call = child_call->sibling_next;
- if (child_call->cancellation_is_inherited) {
- GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
- grpc_call_cancel(child_call, NULL);
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
- }
- child_call = next_child_call;
- } while (child_call != call->first_child);
- }
-
- if (call->is_client) {
- get_final_status(call, set_status_value_directly,
- call->final_op.client.status);
- get_final_details(call, call->final_op.client.status_details,
- call->final_op.client.status_details_capacity);
- } else {
- get_final_status(call, set_cancelled_value,
- call->final_op.server.cancelled);
- }
-
- GRPC_ERROR_UNREF(error);
- error = GRPC_ERROR_NONE;
- }
- add_batch_error(bctl, GRPC_ERROR_REF(error));
- gpr_mu_unlock(&call->mu);
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
-
- GRPC_ERROR_UNREF(error);
+ add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error));
+ finish_batch_step(exec_ctx, bctl);
}
static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
@@ -1377,7 +1340,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (nops == 0) {
GRPC_CALL_INTERNAL_REF(call, "completion");
- bctl->error = GRPC_ERROR_NONE;
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
}
@@ -1426,13 +1388,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
const grpc_compression_algorithm calgo =
compression_algorithm_for_level_locked(
call, effective_compression_level);
- char *calgo_name = NULL;
- grpc_compression_algorithm_name(calgo, &calgo_name);
// the following will be picked up by the compress filter and used as
// the call's compression algorithm.
- compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY;
- compression_md.value = calgo_name;
- compression_md.value_length = strlen(calgo_name);
+ compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST;
+ compression_md.value = grpc_compression_algorithm_slice(calgo);
additional_metadata_count++;
}
@@ -1527,19 +1486,25 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->send_extra_metadata_count = 1;
call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
exec_ctx, call->channel, op->data.send_status_from_server.status);
- if (op->data.send_status_from_server.status_details != NULL) {
- call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_mdstr_from_string(
- op->data.send_status_from_server.status_details));
- call->send_extra_metadata_count++;
- set_status_details(
- exec_ctx, call, STATUS_FROM_API_OVERRIDE,
- GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
- }
- if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
- set_status_code(call, STATUS_FROM_API_OVERRIDE,
- (uint32_t)op->data.send_status_from_server.status);
+ {
+ grpc_error *override_error = GRPC_ERROR_NONE;
+ if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
+ override_error = GRPC_ERROR_CREATE("Error from server send status");
+ }
+ if (op->data.send_status_from_server.status_details != NULL) {
+ call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_slice_ref_internal(
+ *op->data.send_status_from_server.status_details));
+ call->send_extra_metadata_count++;
+ char *msg = grpc_slice_to_c_string(
+ GRPC_MDVALUE(call->send_extra_metadata[1].md));
+ override_error = grpc_error_set_str(
+ override_error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
+ gpr_free(msg);
+ }
+ set_status_from_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE,
+ override_error);
}
if (!prepare_application_metadata(
exec_ctx, call,
@@ -1618,8 +1583,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->final_op.client.status = op->data.recv_status_on_client.status;
call->final_op.client.status_details =
op->data.recv_status_on_client.status_details;
- call->final_op.client.status_details_capacity =
- op->data.recv_status_on_client.status_details_capacity;
bctl->recv_final_op = 1;
stream_op->recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 233340c329..b70343ddf1 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -61,7 +61,7 @@ typedef struct grpc_call_create_args {
const void *server_transport_data;
- grpc_mdelem **add_initial_metadata;
+ grpc_mdelem *add_initial_metadata;
size_t add_initial_metadata_count;
gpr_timespec send_deadline;
@@ -125,6 +125,8 @@ uint8_t grpc_call_is_client(grpc_call *call);
grpc_compression_algorithm grpc_call_compression_for_level(
grpc_call *call, grpc_compression_level level);
+extern int grpc_call_error_trace;
+
#ifdef __cplusplus
}
#endif
diff --git a/src/core/lib/surface/call_details.c b/src/core/lib/surface/call_details.c
index fe73da3f55..d0f88e1969 100644
--- a/src/core/lib/surface/call_details.c
+++ b/src/core/lib/surface/call_details.c
@@ -36,15 +36,21 @@
#include <string.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
void grpc_call_details_init(grpc_call_details* cd) {
GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd));
memset(cd, 0, sizeof(*cd));
+ cd->method = grpc_empty_slice();
+ cd->host = grpc_empty_slice();
}
void grpc_call_details_destroy(grpc_call_details* cd) {
GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd));
- gpr_free(cd->method);
- gpr_free(cd->host);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_slice_unref_internal(&exec_ctx, cd->method);
+ grpc_slice_unref_internal(&exec_ctx, cd->host);
+ grpc_exec_ctx_finish(&exec_ctx);
}
diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c
index 61b73a138f..529a1ef0f5 100644
--- a/src/core/lib/surface/call_log_batch.c
+++ b/src/core/lib/surface/call_log_batch.c
@@ -35,17 +35,22 @@
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
size_t i;
+ if (md == NULL) {
+ gpr_strvec_add(b, gpr_strdup("(nil)"));
+ return;
+ }
for (i = 0; i < count; i++) {
gpr_strvec_add(b, gpr_strdup("\nkey="));
- gpr_strvec_add(b, gpr_strdup(md[i].key));
+ gpr_strvec_add(b, grpc_slice_to_c_string(md[i].key));
gpr_strvec_add(b, gpr_strdup(" value="));
- gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length,
- GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ gpr_strvec_add(b,
+ grpc_dump_slice(md[i].value, GPR_DUMP_HEX | GPR_DUMP_ASCII));
}
}
@@ -71,10 +76,16 @@ char *grpc_op_string(const grpc_op *op) {
gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
- gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
- op->data.send_status_from_server.status,
- op->data.send_status_from_server.status_details);
+ gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=",
+ op->data.send_status_from_server.status);
gpr_strvec_add(&b, tmp);
+ if (op->data.send_status_from_server.status_details != NULL) {
+ gpr_strvec_add(&b, grpc_dump_slice(
+ *op->data.send_status_from_server.status_details,
+ GPR_DUMP_ASCII));
+ } else {
+ gpr_strvec_add(&b, gpr_strdup("(null)"));
+ }
add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
op->data.send_status_from_server.trailing_metadata_count);
break;
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index b87295786e..429dbad7c7 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -43,6 +43,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -57,15 +58,15 @@
#define NUM_CACHED_STATUS_ELEMS 3
typedef struct registered_call {
- grpc_mdelem *path;
- grpc_mdelem *authority;
+ grpc_mdelem path;
+ grpc_mdelem authority;
struct registered_call *next;
} registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
- grpc_mdelem *default_authority;
+ grpc_mdelem default_authority;
gpr_mu registered_call_mu;
registered_call *registered_calls;
@@ -102,9 +103,8 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
exec_ctx, builder, sizeof(grpc_channel), 1, destroy_channel, NULL,
(void **)&channel);
if (error != GRPC_ERROR_NONE) {
- const char *msg = grpc_error_string(error);
- gpr_log(GPR_ERROR, "channel stack builder failed: %s", msg);
- grpc_error_free_string(msg);
+ gpr_log(GPR_ERROR, "channel stack builder failed: %s",
+ grpc_error_string(error));
GRPC_ERROR_UNREF(error);
goto done;
}
@@ -116,19 +116,19 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
channel->registered_calls = NULL;
grpc_compression_options_init(&channel->compression_options);
-
for (size_t i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
if (args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
- if (channel->default_authority) {
+ if (!GRPC_MDISNULL(channel->default_authority)) {
/* setting this takes precedence over anything else */
GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
}
- channel->default_authority = grpc_mdelem_from_strings(
- exec_ctx, ":authority", args->args[i].value.string);
+ channel->default_authority = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_from_copied_string(args->args[i].value.string));
}
} else if (0 ==
strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
@@ -136,14 +136,15 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
- if (channel->default_authority) {
+ if (!GRPC_MDISNULL(channel->default_authority)) {
/* other ways of setting this (notably ssl) take precedence */
gpr_log(GPR_ERROR,
"%s ignored: default host already set some other way",
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
- channel->default_authority = grpc_mdelem_from_strings(
- exec_ctx, ":authority", args->args[i].value.string);
+ channel->default_authority = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_from_copied_string(args->args[i].value.string));
}
}
} else if (0 == strcmp(args->args[i].key,
@@ -191,18 +192,18 @@ void grpc_channel_get_info(grpc_channel *channel,
static grpc_call *grpc_channel_create_call_internal(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
uint32_t propagation_mask, grpc_completion_queue *cq,
- grpc_pollset_set *pollset_set_alternative, grpc_mdelem *path_mdelem,
- grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
- grpc_mdelem *send_metadata[2];
+ grpc_pollset_set *pollset_set_alternative, grpc_mdelem path_mdelem,
+ grpc_mdelem authority_mdelem, gpr_timespec deadline) {
+ grpc_mdelem send_metadata[2];
size_t num_metadata = 0;
GPR_ASSERT(channel->is_client);
GPR_ASSERT(!(cq != NULL && pollset_set_alternative != NULL));
send_metadata[num_metadata++] = path_mdelem;
- if (authority_mdelem != NULL) {
+ if (!GRPC_MDISNULL(authority_mdelem)) {
send_metadata[num_metadata++] = authority_mdelem;
- } else if (channel->default_authority != NULL) {
+ } else if (!GRPC_MDISNULL(channel->default_authority)) {
send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
}
@@ -227,27 +228,17 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *parent_call,
uint32_t propagation_mask,
grpc_completion_queue *cq,
- const char *method, const char *host,
+ grpc_slice method, const grpc_slice *host,
gpr_timespec deadline, void *reserved) {
- GRPC_API_TRACE(
- "grpc_channel_create_call("
- "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
- "host=%s, "
- "deadline=gpr_timespec { tv_sec: %" PRId64
- ", tv_nsec: %d, clock_type: %d }, "
- "reserved=%p)",
- 10,
- (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
- deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_call *call = grpc_channel_create_call_internal(
&exec_ctx, channel, parent_call, propagation_mask, cq, NULL,
- grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
- grpc_mdstr_from_string(method)),
- host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_mdstr_from_string(host))
- : NULL,
+ grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_PATH,
+ grpc_slice_ref_internal(method)),
+ host != NULL ? grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_ref_internal(*host))
+ : GRPC_MDNULL,
deadline);
grpc_exec_ctx_finish(&exec_ctx);
return call;
@@ -255,17 +246,16 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *grpc_channel_create_pollset_set_call(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
- uint32_t propagation_mask, grpc_pollset_set *pollset_set,
- const char *method, const char *host, gpr_timespec deadline,
- void *reserved) {
+ uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
+ const grpc_slice *host, gpr_timespec deadline, void *reserved) {
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
exec_ctx, channel, parent_call, propagation_mask, NULL, pollset_set,
- grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_PATH,
- grpc_mdstr_from_string(method)),
- host ? grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_mdstr_from_string(host))
- : NULL,
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH,
+ grpc_slice_ref_internal(method)),
+ host != NULL ? grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_ref_internal(*host))
+ : GRPC_MDNULL,
deadline);
}
@@ -277,12 +267,15 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
4, (channel, method, host, reserved));
GPR_ASSERT(!reserved);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- rc->path = grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
- grpc_mdstr_from_string(method));
+
+ rc->path = grpc_mdelem_from_slices(
+ &exec_ctx, GRPC_MDSTR_PATH,
+ grpc_slice_intern(grpc_slice_from_static_string(method)));
rc->authority =
- host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_mdstr_from_string(host))
- : NULL;
+ host ? grpc_mdelem_from_slices(
+ &exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_intern(grpc_slice_from_static_string(host)))
+ : GRPC_MDNULL;
gpr_mu_lock(&channel->registered_call_mu);
rc->next = channel->registered_calls;
channel->registered_calls = rc;
@@ -310,8 +303,7 @@ grpc_call *grpc_channel_create_registered_call(
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_call *call = grpc_channel_create_call_internal(
&exec_ctx, channel, parent_call, propagation_mask, completion_queue, NULL,
- GRPC_MDELEM_REF(rc->path),
- rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
+ GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority), deadline);
grpc_exec_ctx_finish(&exec_ctx);
return call;
}
@@ -340,14 +332,10 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
registered_call *rc = channel->registered_calls;
channel->registered_calls = rc->next;
GRPC_MDELEM_UNREF(exec_ctx, rc->path);
- if (rc->authority) {
- GRPC_MDELEM_UNREF(exec_ctx, rc->authority);
- }
+ GRPC_MDELEM_UNREF(exec_ctx, rc->authority);
gpr_free(rc);
}
- if (channel->default_authority != NULL) {
- GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
- }
+ GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
@@ -376,8 +364,8 @@ grpc_compression_options grpc_channel_compression_options(
return channel->compression_options;
}
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel *channel, int i) {
+grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+ grpc_channel *channel, int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
case 0:
@@ -388,6 +376,6 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
return GRPC_MDELEM_GRPC_STATUS_2;
}
gpr_ltoa(i, tmp);
- return grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
- grpc_mdstr_from_string(tmp));
+ return grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
+ grpc_slice_from_copied_string(tmp));
}
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 2ebadb7a15..3a441d7add 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -52,9 +52,8 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
value of \a propagation_mask (see propagation_bits.h for possible values) */
grpc_call *grpc_channel_create_pollset_set_call(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
- uint32_t propagation_mask, grpc_pollset_set *pollset_set,
- const char *method, const char *host, gpr_timespec deadline,
- void *reserved);
+ uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
+ const grpc_slice *host, gpr_timespec deadline, void *reserved);
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
@@ -63,9 +62,9 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
status_code.
The returned elem is owned by the caller. */
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel *channel,
- int status_code);
+grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+ grpc_channel *channel,
+ int status_code);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 4613c9021e..1830842d00 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -253,7 +253,6 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
if (grpc_trace_operation_failures && error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
}
- grpc_error_free_string(errmsg);
}
storage->tag = tag;
@@ -294,7 +293,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
if (kick_error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(kick_error);
gpr_log(GPR_ERROR, "Kick failed: %s", msg);
- grpc_error_free_string(msg);
+
GRPC_ERROR_UNREF(kick_error);
}
} else {
@@ -403,8 +402,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
.stolen_completion = NULL,
.tag = NULL,
.first_loop = true};
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
- cq_is_next_finished, &is_finished_arg);
+ grpc_exec_ctx exec_ctx =
+ GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg);
for (;;) {
if (is_finished_arg.stolen_completion != NULL) {
gpr_mu_unlock(cc->mu);
@@ -461,7 +460,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
- grpc_error_free_string(msg);
+
GRPC_ERROR_UNREF(err);
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
@@ -572,8 +571,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
.stolen_completion = NULL,
.tag = tag,
.first_loop = true};
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
- cq_is_pluck_finished, &is_finished_arg);
+ grpc_exec_ctx exec_ctx =
+ GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg);
for (;;) {
if (is_finished_arg.stolen_completion != NULL) {
gpr_mu_unlock(cc->mu);
@@ -647,7 +646,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
- grpc_error_free_string(msg);
+
GRPC_ERROR_UNREF(err);
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index f61bf1582e..b338ac4c48 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -55,6 +55,7 @@
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
@@ -62,6 +63,7 @@
#include "src/core/lib/surface/init.h"
#include "src/core/lib/surface/lame_client.h"
#include "src/core/lib/surface/server.h"
+#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/transport_impl.h"
@@ -178,6 +180,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
+ grpc_slice_intern_init();
grpc_mdctx_global_init();
grpc_channel_init_init();
grpc_register_tracer("api", &grpc_api_trace);
@@ -190,6 +193,7 @@ void grpc_init(void) {
grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace);
grpc_register_tracer("combiner", &grpc_combiner_trace);
grpc_register_tracer("server_channel", &grpc_server_channel_trace);
+ grpc_register_tracer("bdp_estimator", &grpc_bdp_estimator_trace);
// Default pluck trace to 1
grpc_cq_pluck_trace = 1;
grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace);
@@ -197,6 +201,7 @@ void grpc_init(void) {
grpc_cq_event_timeout_trace = 1;
grpc_register_tracer("op_failure", &grpc_trace_operation_failures);
grpc_register_tracer("resource_quota", &grpc_resource_quota_trace);
+ grpc_register_tracer("call_error", &grpc_call_error_trace);
#ifndef NDEBUG
grpc_register_tracer("pending_tags", &grpc_trace_pending_tags);
#endif
@@ -242,6 +247,7 @@ void grpc_shutdown(void) {
}
grpc_mdctx_global_shutdown(&exec_ctx);
grpc_handshaker_factory_registry_shutdown(&exec_ctx);
+ grpc_slice_intern_shutdown();
}
gpr_mu_unlock(&g_init_mu);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index ae1eac09a9..48de0e1d5b 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -44,10 +44,12 @@
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/static_metadata.h"
typedef struct {
grpc_linked_mdelem status;
grpc_linked_mdelem details;
+ gpr_atm filled_metadata;
} call_data;
typedef struct {
@@ -58,17 +60,23 @@ typedef struct {
static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_metadata_batch *mdb) {
call_data *calld = elem->call_data;
+ if (!gpr_atm_no_barrier_cas(&calld->filled_metadata, 0, 1)) {
+ return;
+ }
channel_data *chand = elem->channel_data;
char tmp[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(chand->error_code, tmp);
- calld->status.md = grpc_mdelem_from_strings(exec_ctx, "grpc-status", tmp);
- calld->details.md =
- grpc_mdelem_from_strings(exec_ctx, "grpc-message", chand->error_message);
+ calld->status.md = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_GRPC_STATUS, grpc_slice_from_copied_string(tmp));
+ calld->details.md = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_slice_from_copied_string(chand->error_message));
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
mdb->list.head = &calld->status;
mdb->list.tail = &calld->details;
+ mdb->list.count = 2;
mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
@@ -115,6 +123,8 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_call_element_args *args) {
+ call_data *calld = elem->call_data;
+ gpr_atm_no_barrier_store(&calld->filled_metadata, 0);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 9e916465be..6ab1c0d94d 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -98,8 +98,9 @@ typedef struct requested_call {
typedef struct channel_registered_method {
registered_method *server_registered_method;
uint32_t flags;
- grpc_mdstr *method;
- grpc_mdstr *host;
+ bool has_host;
+ grpc_slice method;
+ grpc_slice host;
} channel_registered_method;
struct channel_data {
@@ -144,8 +145,10 @@ struct call_data {
/** the current state of a call - see call_state */
call_state state;
- grpc_mdstr *path;
- grpc_mdstr *host;
+ bool path_set;
+ bool host_set;
+ grpc_slice path;
+ grpc_slice host;
gpr_timespec deadline;
grpc_completion_queue *cq_new;
@@ -277,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,
- int send_goaway, grpc_error *send_disconnect) {
+ bool send_goaway, grpc_error *send_disconnect) {
struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
grpc_closure_init(&sc->closure, shutdown_cleanup, sc,
grpc_schedule_on_exec_ctx);
grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
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;
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;
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
@@ -448,7 +453,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
if (grpc_server_channel_trace && error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_INFO, "Disconnected client: %s", msg);
- grpc_error_free_string(msg);
}
GRPC_ERROR_UNREF(error);
@@ -461,17 +465,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
op);
}
-static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
- grpc_slice slice = value->slice;
- size_t len = GRPC_SLICE_LENGTH(slice);
-
- if (len + 1 > *capacity) {
- *capacity = GPR_MAX(len + 1, *capacity * 2);
- *dest = gpr_realloc(*dest, *capacity);
- }
- memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1);
-}
-
static void done_request_event(grpc_exec_ctx *exec_ctx, void *req,
grpc_cq_completion *c) {
requested_call *rc = req;
@@ -500,12 +493,10 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata);
switch (rc->type) {
case BATCH_CALL:
- GPR_ASSERT(calld->host != NULL);
- GPR_ASSERT(calld->path != NULL);
- cpstr(&rc->data.batch.details->host,
- &rc->data.batch.details->host_capacity, calld->host);
- cpstr(&rc->data.batch.details->method,
- &rc->data.batch.details->method_capacity, calld->path);
+ GPR_ASSERT(calld->host_set);
+ GPR_ASSERT(calld->path_set);
+ rc->data.batch.details->host = grpc_slice_ref_internal(calld->host);
+ rc->data.batch.details->method = grpc_slice_ref_internal(calld->path);
rc->data.batch.details->deadline = calld->deadline;
rc->data.batch.details->flags =
(calld->recv_idempotent_request
@@ -627,35 +618,39 @@ static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
uint32_t hash;
channel_registered_method *rm;
- if (chand->registered_methods && calld->path && calld->host) {
+ if (chand->registered_methods && calld->path_set && calld->host_set) {
/* TODO(ctiller): unify these two searches */
/* check for an exact match with host */
- hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
+ hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host),
+ grpc_slice_hash(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
if (!rm) break;
- if (rm->host != calld->host) continue;
- if (rm->method != calld->path) continue;
+ if (!rm->has_host) continue;
+ if (!grpc_slice_eq(rm->host, calld->host)) continue;
+ if (!grpc_slice_eq(rm->method, calld->path)) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request)
+ !calld->recv_idempotent_request) {
continue;
+ }
finish_start_new_rpc(exec_ctx, server, elem,
&rm->server_registered_method->request_matcher,
rm->server_registered_method->payload_handling);
return;
}
/* check for a wildcard method definition (no host set) */
- hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash);
+ hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
if (!rm) break;
- if (rm->host != NULL) continue;
- if (rm->method != calld->path) continue;
+ if (rm->has_host) continue;
+ if (!grpc_slice_eq(rm->method, calld->path)) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request)
+ !calld->recv_idempotent_request) {
continue;
+ }
finish_start_new_rpc(exec_ctx, server, elem,
&rm->server_registered_method->request_matcher,
rm->server_registered_method->payload_handling);
@@ -744,43 +739,40 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
}
}
-static grpc_mdelem *server_filter(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
- call_data *calld = elem->call_data;
- if (md->key == GRPC_MDSTR_PATH) {
- if (calld->path == NULL) {
- calld->path = GRPC_MDSTR_REF(md->value);
- }
- return NULL;
- } else if (md->key == GRPC_MDSTR_AUTHORITY) {
- if (calld->host == NULL) {
- calld->host = GRPC_MDSTR_REF(md->value);
- }
- return NULL;
- }
- return md;
-}
-
static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
grpc_error *error) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
gpr_timespec op_deadline;
- GRPC_ERROR_REF(error);
- grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
- server_filter, elem);
+ if (error == GRPC_ERROR_NONE) {
+ GPR_ASSERT(calld->recv_initial_metadata->idx.named.path != NULL);
+ GPR_ASSERT(calld->recv_initial_metadata->idx.named.authority != NULL);
+ calld->path = grpc_slice_ref_internal(
+ GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md));
+ calld->host = grpc_slice_ref_internal(
+ GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.authority->md));
+ calld->path_set = true;
+ calld->host_set = true;
+ grpc_metadata_batch_remove(exec_ctx, calld->recv_initial_metadata,
+ calld->recv_initial_metadata->idx.named.path);
+ grpc_metadata_batch_remove(
+ exec_ctx, calld->recv_initial_metadata,
+ calld->recv_initial_metadata->idx.named.authority);
+ } else {
+ GRPC_ERROR_REF(error);
+ }
op_deadline = calld->recv_initial_metadata->deadline;
if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
calld->deadline = op_deadline;
}
- if (calld->host && calld->path) {
+ if (calld->host_set && calld->path_set) {
/* do nothing */
} else {
- GRPC_ERROR_UNREF(error);
+ grpc_error *src_error = error;
error =
GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1);
+ GRPC_ERROR_UNREF(src_error);
}
grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error);
@@ -911,11 +903,11 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
GPR_ASSERT(calld->state != PENDING);
- if (calld->host) {
- GRPC_MDSTR_UNREF(exec_ctx, calld->host);
+ if (calld->host_set) {
+ grpc_slice_unref_internal(exec_ctx, calld->host);
}
- if (calld->path) {
- GRPC_MDSTR_UNREF(exec_ctx, calld->path);
+ if (calld->path_set) {
+ grpc_slice_unref_internal(exec_ctx, calld->path);
}
grpc_metadata_array_destroy(&calld->initial_metadata);
@@ -947,11 +939,9 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data;
if (chand->registered_methods) {
for (i = 0; i < chand->registered_method_slots; i++) {
- if (chand->registered_methods[i].method) {
- GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].method);
- }
- if (chand->registered_methods[i].host) {
- GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].host);
+ grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].method);
+ if (chand->registered_methods[i].has_host) {
+ grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].host);
}
}
gpr_free(chand->registered_methods);
@@ -1149,8 +1139,6 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
channel_registered_method *crm;
grpc_channel *channel;
channel_data *chand;
- grpc_mdstr *host;
- grpc_mdstr *method;
uint32_t hash;
size_t slots;
uint32_t probes;
@@ -1189,9 +1177,18 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
chand->registered_methods = gpr_malloc(alloc);
memset(chand->registered_methods, 0, alloc);
for (rm = s->registered_methods; rm; rm = rm->next) {
- host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL;
- method = grpc_mdstr_from_string(rm->method);
- hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
+ grpc_slice host;
+ bool has_host;
+ grpc_slice method;
+ if (rm->host != NULL) {
+ host = grpc_slice_intern(grpc_slice_from_static_string(rm->host));
+ has_host = true;
+ } else {
+ has_host = false;
+ }
+ method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
+ hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0,
+ grpc_slice_hash(method));
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != NULL;
probes++)
@@ -1200,6 +1197,7 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
crm = &chand->registered_methods[(hash + probes) % slots];
crm->server_registered_method = rm;
crm->flags = rm->flags;
+ crm->has_host = has_host;
crm->host = host;
crm->method = method;
}
diff --git a/src/core/lib/surface/validate_metadata.c b/src/core/lib/surface/validate_metadata.c
index f49dd8584b..7ec9137265 100644
--- a/src/core/lib/surface/validate_metadata.c
+++ b/src/core/lib/surface/validate_metadata.c
@@ -34,40 +34,71 @@
#include <stdlib.h>
#include <string.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/port_platform.h>
-static int conforms_to(const char *s, size_t len, const uint8_t *legal_bits) {
- const char *p = s;
- const char *e = s + len;
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+
+static grpc_error *conforms_to(grpc_slice slice, const uint8_t *legal_bits,
+ const char *err_desc) {
+ const uint8_t *p = GRPC_SLICE_START_PTR(slice);
+ const uint8_t *e = GRPC_SLICE_END_PTR(slice);
for (; p != e; p++) {
- int idx = (uint8_t)*p;
+ int idx = *p;
int byte = idx / 8;
int bit = idx % 8;
- if ((legal_bits[byte] & (1 << bit)) == 0) return 0;
+ if ((legal_bits[byte] & (1 << bit)) == 0) {
+ char *dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ grpc_error *error = grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE(err_desc), GRPC_ERROR_INT_OFFSET,
+ p - GRPC_SLICE_START_PTR(slice)),
+ GRPC_ERROR_STR_RAW_BYTES, dump);
+ gpr_free(dump);
+ return error;
+ }
}
- return 1;
+ return GRPC_ERROR_NONE;
+}
+
+static int error2int(grpc_error *error) {
+ int r = (error == GRPC_ERROR_NONE);
+ GRPC_ERROR_UNREF(error);
+ return r;
}
-int grpc_header_key_is_legal(const char *key, size_t length) {
+grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- if (length == 0 || key[0] == ':') {
- return 0;
+ if (GRPC_SLICE_LENGTH(slice) == 0) {
+ return GRPC_ERROR_CREATE("Metadata keys cannot be zero length");
+ }
+ if (GRPC_SLICE_START_PTR(slice)[0] == ':') {
+ return GRPC_ERROR_CREATE("Metadata keys cannot start with :");
}
- return conforms_to(key, length, legal_header_bits);
+ return conforms_to(slice, legal_header_bits, "Illegal header key");
}
-int grpc_header_nonbin_value_is_legal(const char *value, size_t length) {
+int grpc_header_key_is_legal(grpc_slice slice) {
+ return error2int(grpc_validate_header_key_is_legal(slice));
+}
+
+grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- return conforms_to(value, length, legal_header_bits);
+ return conforms_to(slice, legal_header_bits, "Illegal header value");
+}
+
+int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
+ return error2int(grpc_validate_header_nonbin_value_is_legal(slice));
}
-int grpc_is_binary_header(const char *key, size_t length) {
- if (length < 5) return 0;
- return 0 == memcmp(key + length - 4, "-bin", 4);
+int grpc_is_binary_header(grpc_slice slice) {
+ if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
+ return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
}
diff --git a/src/core/lib/surface/validate_metadata.h b/src/core/lib/surface/validate_metadata.h
new file mode 100644
index 0000000000..2b800d25a4
--- /dev/null
+++ b/src/core/lib/surface/validate_metadata.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H
+#define GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H
+
+#include <grpc/slice.h>
+#include "src/core/lib/iomgr/error.h"
+
+grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice);
+grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
+
+#endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 0db8b41aa9..1143a9e044 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,6 +36,6 @@
#include <grpc/grpc.h>
-const char *grpc_version_string(void) { return "2.0.0-dev"; }
+const char *grpc_version_string(void) { return "3.0.0-dev"; }
-const char *grpc_g_stands_for(void) { return "good"; }
+const char *grpc_g_stands_for(void) { return "green"; }
diff --git a/src/core/lib/transport/bdp_estimator.c b/src/core/lib/transport/bdp_estimator.c
new file mode 100644
index 0000000000..e1483677fd
--- /dev/null
+++ b/src/core/lib/transport/bdp_estimator.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/bdp_estimator.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+int grpc_bdp_estimator_trace = 0;
+
+void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) {
+ estimator->estimate = 65536;
+ estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
+ estimator->name = name;
+}
+
+bool grpc_bdp_estimator_get_estimate(grpc_bdp_estimator *estimator,
+ int64_t *estimate) {
+ *estimate = estimator->estimate;
+ return true;
+}
+
+bool grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
+ int64_t num_bytes) {
+ estimator->accumulator += num_bytes;
+ switch (estimator->ping_state) {
+ case GRPC_BDP_PING_UNSCHEDULED:
+ return true;
+ case GRPC_BDP_PING_SCHEDULED:
+ return false;
+ case GRPC_BDP_PING_STARTED:
+ return false;
+ }
+ GPR_UNREACHABLE_CODE(return false);
+}
+
+void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator) {
+ if (grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64,
+ estimator->name, estimator->accumulator, estimator->estimate);
+ }
+ GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_UNSCHEDULED);
+ estimator->ping_state = GRPC_BDP_PING_SCHEDULED;
+ estimator->accumulator = 0;
+}
+
+void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator) {
+ if (grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64,
+ estimator->name, estimator->accumulator, estimator->estimate);
+ }
+ GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_SCHEDULED);
+ estimator->ping_state = GRPC_BDP_PING_STARTED;
+ estimator->accumulator = 0;
+}
+
+void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator) {
+ if (grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64,
+ estimator->name, estimator->accumulator, estimator->estimate);
+ }
+ GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_STARTED);
+ if (estimator->accumulator > 2 * estimator->estimate / 3) {
+ estimator->estimate *= 2;
+ if (grpc_bdp_estimator_trace) {
+ gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64,
+ estimator->name, estimator->estimate);
+ }
+ }
+ estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
+ estimator->accumulator = 0;
+}
diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h
new file mode 100644
index 0000000000..bcaf899910
--- /dev/null
+++ b/src/core/lib/transport/bdp_estimator.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
+#define GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define GRPC_BDP_SAMPLES 16
+#define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3
+
+extern int grpc_bdp_estimator_trace;
+
+typedef enum {
+ GRPC_BDP_PING_UNSCHEDULED,
+ GRPC_BDP_PING_SCHEDULED,
+ GRPC_BDP_PING_STARTED
+} grpc_bdp_estimator_ping_state;
+
+typedef struct grpc_bdp_estimator {
+ grpc_bdp_estimator_ping_state ping_state;
+ int64_t accumulator;
+ int64_t estimate;
+ const char *name;
+} grpc_bdp_estimator;
+
+void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name);
+
+// Returns true if a reasonable estimate could be obtained
+bool grpc_bdp_estimator_get_estimate(grpc_bdp_estimator *estimator,
+ int64_t *estimate);
+// Returns true if the user should schedule a ping
+bool grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
+ int64_t num_bytes);
+// Schedule a ping: call in response to receiving a true from
+// grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
+// transport (but not necessarily started)
+void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator);
+// Start a ping: call after calling grpc_bdp_estimator_schedule_ping and once
+// the ping is on the wire
+void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator);
+// Completes a previously started ping
+void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator);
+
+#endif
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
index c656d93740..8fc5bf3e9a 100644
--- a/src/core/lib/transport/connectivity_state.c
+++ b/src/core/lib/transport/connectivity_state.c
@@ -163,7 +163,6 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker,
tracker->name, grpc_connectivity_state_name(tracker->current_state),
grpc_connectivity_state_name(state), reason, error, error_string);
- grpc_error_free_string(error_string);
}
switch (state) {
case GRPC_CHANNEL_INIT:
diff --git a/src/core/lib/transport/error_utils.c b/src/core/lib/transport/error_utils.c
new file mode 100644
index 0000000000..da77828d9c
--- /dev/null
+++ b/src/core/lib/transport/error_utils.c
@@ -0,0 +1,124 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/error_utils.h"
+
+#include "src/core/lib/iomgr/error_internal.h"
+#include "src/core/lib/transport/status_conversion.h"
+
+static grpc_error *recursively_find_error_with_field(grpc_error *error,
+ grpc_error_ints which) {
+ // If the error itself has a status code, return it.
+ if (grpc_error_get_int(error, which, NULL)) {
+ return error;
+ }
+ if (grpc_error_is_special(error)) return NULL;
+ // Otherwise, search through its children.
+ intptr_t key = 0;
+ while (true) {
+ grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
+ if (child_error == NULL) break;
+ grpc_error *result = recursively_find_error_with_field(child_error, which);
+ if (result != NULL) return result;
+ }
+ return NULL;
+}
+
+void grpc_error_get_status(grpc_error *error, gpr_timespec deadline,
+ grpc_status_code *code, const char **msg,
+ grpc_http2_error_code *http_error) {
+ // Start with the parent error and recurse through the tree of children
+ // until we find the first one that has a status code.
+ grpc_error *found_error =
+ recursively_find_error_with_field(error, GRPC_ERROR_INT_GRPC_STATUS);
+ if (found_error == NULL) {
+ /// 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,
+ // fall back to using the parent 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
+ // the error description.
+ if (msg != NULL) {
+ *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE);
+ if (*msg == NULL && error != GRPC_ERROR_NONE) {
+ *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) {
+ if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
+ return true;
+ }
+ intptr_t key = 0;
+ while (true) {
+ grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
+ if (child_error == NULL) break;
+ if (grpc_error_has_clear_grpc_status(child_error)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/core/lib/transport/error_utils.h b/src/core/lib/transport/error_utils.h
new file mode 100644
index 0000000000..105338880a
--- /dev/null
+++ b/src/core/lib/transport/error_utils.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H
+#define GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_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
+/// to the application. If not set in the top-level message, looks
+/// through child errors until it finds the first one with these attributes.
+/// All attributes are pulled from the same child error. If any of the
+/// 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
+/// 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
+/// GRPC_ERROR_CANCELLED
+bool grpc_error_has_clear_grpc_status(grpc_error *error);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H */
diff --git a/src/core/ext/transport/chttp2/transport/http2_errors.h b/src/core/lib/transport/http2_errors.h
index deab2b7e3e..330bc987f6 100644
--- a/src/core/ext/transport/chttp2/transport/http2_errors.h
+++ b/src/core/lib/transport/http2_errors.h
@@ -31,26 +31,26 @@
*
*/
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H
+#ifndef GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H
+#define GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H
/* error codes for RST_STREAM from http2 draft 14 section 7 */
typedef enum {
- GRPC_CHTTP2_NO_ERROR = 0x0,
- GRPC_CHTTP2_PROTOCOL_ERROR = 0x1,
- GRPC_CHTTP2_INTERNAL_ERROR = 0x2,
- GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3,
- GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4,
- GRPC_CHTTP2_STREAM_CLOSED = 0x5,
- GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6,
- GRPC_CHTTP2_REFUSED_STREAM = 0x7,
- GRPC_CHTTP2_CANCEL = 0x8,
- GRPC_CHTTP2_COMPRESSION_ERROR = 0x9,
- GRPC_CHTTP2_CONNECT_ERROR = 0xa,
- GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb,
- GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc,
+ GRPC_HTTP2_NO_ERROR = 0x0,
+ GRPC_HTTP2_PROTOCOL_ERROR = 0x1,
+ GRPC_HTTP2_INTERNAL_ERROR = 0x2,
+ GRPC_HTTP2_FLOW_CONTROL_ERROR = 0x3,
+ GRPC_HTTP2_SETTINGS_TIMEOUT = 0x4,
+ GRPC_HTTP2_STREAM_CLOSED = 0x5,
+ GRPC_HTTP2_FRAME_SIZE_ERROR = 0x6,
+ GRPC_HTTP2_REFUSED_STREAM = 0x7,
+ GRPC_HTTP2_CANCEL = 0x8,
+ GRPC_HTTP2_COMPRESSION_ERROR = 0x9,
+ GRPC_HTTP2_CONNECT_ERROR = 0xa,
+ GRPC_HTTP2_ENHANCE_YOUR_CALM = 0xb,
+ GRPC_HTTP2_INADEQUATE_SECURITY = 0xc,
/* force use of a default clause */
- GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
-} grpc_chttp2_error_code;
+ GRPC_HTTP2__ERROR_DO_NOT_USE = -1
+} grpc_http2_error_code;
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H */
+#endif /* GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H */
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 54c39df6a7..489c20cbc8 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -48,12 +48,11 @@
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/murmur_hash.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
-grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input);
-
/* There are two kinds of mdelem and mdstr instances.
* Static instances are declared in static_metadata.{h,c} and
* are initialized by grpc_mdctx_global_init().
@@ -63,9 +62,6 @@ grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input);
* used to determine which kind of element a pointer refers to.
*/
-#define INITIAL_STRTAB_CAPACITY 4
-#define INITIAL_MDTAB_CAPACITY 4
-
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
#define DEBUG_ARGS , const char *file, int line
#define FWD_DEBUG_ARGS , file, line
@@ -76,37 +72,20 @@ grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input);
#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
#endif
-#define TABLE_IDX(hash, log2_shards, capacity) \
- (((hash) >> (log2_shards)) % (capacity))
-#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
-
-typedef void (*destroy_user_data_func)(void *user_data);
-
-#define SIZE_IN_DECODER_TABLE_NOT_SET -1
-/* Shadow structure for grpc_mdstr for non-static values */
-typedef struct internal_string {
- /* must be byte compatible with grpc_mdstr */
- grpc_slice slice;
- uint32_t hash;
-
- /* private only data */
- gpr_atm refcnt;
-
- uint8_t has_base64_and_huffman_encoded;
- grpc_slice_refcount refcount;
+#define INITIAL_SHARD_CAPACITY 8
+#define LOG2_SHARD_COUNT 4
+#define SHARD_COUNT ((size_t)(1 << LOG2_SHARD_COUNT))
- grpc_slice base64_and_huffman;
+#define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity))
+#define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1))
- gpr_atm size_in_decoder_table;
-
- struct internal_string *bucket_next;
-} internal_string;
+typedef void (*destroy_user_data_func)(void *user_data);
-/* Shadow structure for grpc_mdelem for non-static elements */
-typedef struct internal_metadata {
- /* must be byte compatible with grpc_mdelem */
- internal_string *key;
- internal_string *value;
+/* Shadow structure for grpc_mdelem_data for interned elements */
+typedef struct interned_metadata {
+ /* must be byte compatible with grpc_mdelem_data */
+ grpc_slice key;
+ grpc_slice value;
/* private only data */
gpr_atm refcnt;
@@ -115,19 +94,22 @@ typedef struct internal_metadata {
gpr_atm destroy_user_data;
gpr_atm user_data;
- struct internal_metadata *bucket_next;
-} internal_metadata;
+ struct interned_metadata *bucket_next;
+} interned_metadata;
-typedef struct strtab_shard {
- gpr_mu mu;
- internal_string **strs;
- size_t count;
- size_t capacity;
-} strtab_shard;
+/* Shadow structure for grpc_mdelem_data for allocated elements */
+typedef struct allocated_metadata {
+ /* must be byte compatible with grpc_mdelem_data */
+ grpc_slice key;
+ grpc_slice value;
+
+ /* private only data */
+ gpr_atm refcnt;
+} allocated_metadata;
typedef struct mdtab_shard {
gpr_mu mu;
- internal_metadata **elems;
+ interned_metadata **elems;
size_t count;
size_t capacity;
/** Estimate of the number of unreferenced mdelems in the hash table.
@@ -136,102 +118,26 @@ typedef struct mdtab_shard {
gpr_atm free_estimate;
} mdtab_shard;
-#define LOG2_STRTAB_SHARD_COUNT 5
-#define LOG2_MDTAB_SHARD_COUNT 4
-#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
-#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
-
-/* hash seed: decided at initialization time */
-static uint32_t g_hash_seed;
-static int g_forced_hash_seed = 0;
-
-/* linearly probed hash tables for static element lookup */
-static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
-static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
-static size_t g_static_strtab_maxprobe;
-static size_t g_static_mdtab_maxprobe;
-
-static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
-static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
+static mdtab_shard g_shards[SHARD_COUNT];
static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard);
-void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
- g_hash_seed = seed;
- g_forced_hash_seed = 1;
-}
-
void grpc_mdctx_global_init(void) {
- size_t i, j;
- if (!g_forced_hash_seed) {
- g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
- }
- g_static_strtab_maxprobe = 0;
- g_static_mdtab_maxprobe = 0;
- /* build static tables */
- memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
- memset(g_static_strtab, 0, sizeof(g_static_strtab));
- for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
- grpc_mdstr *elem = &grpc_static_mdstr_table[i];
- const char *str = grpc_static_metadata_strings[i];
- uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
- *(grpc_slice *)&elem->slice = grpc_slice_from_static_string(str);
- *(uint32_t *)&elem->hash = hash;
- for (j = 0;; j++) {
- size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
- if (g_static_strtab[idx] == NULL) {
- g_static_strtab[idx] = &grpc_static_mdstr_table[i];
- break;
- }
- }
- if (j > g_static_strtab_maxprobe) {
- g_static_strtab_maxprobe = j;
- }
- }
- for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
- grpc_mdelem *elem = &grpc_static_mdelem_table[i];
- grpc_mdstr *key =
- &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
- grpc_mdstr *value =
- &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
- uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
- *(grpc_mdstr **)&elem->key = key;
- *(grpc_mdstr **)&elem->value = value;
- for (j = 0;; j++) {
- size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
- if (g_static_mdtab[idx] == NULL) {
- g_static_mdtab[idx] = elem;
- break;
- }
- }
- if (j > g_static_mdtab_maxprobe) {
- g_static_mdtab_maxprobe = j;
- }
- }
/* initialize shards */
- for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
- strtab_shard *shard = &g_strtab_shard[i];
- gpr_mu_init(&shard->mu);
- shard->count = 0;
- shard->capacity = INITIAL_STRTAB_CAPACITY;
- shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
- memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
- }
- for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
- mdtab_shard *shard = &g_mdtab_shard[i];
+ for (size_t i = 0; i < SHARD_COUNT; i++) {
+ mdtab_shard *shard = &g_shards[i];
gpr_mu_init(&shard->mu);
shard->count = 0;
gpr_atm_no_barrier_store(&shard->free_estimate, 0);
- shard->capacity = INITIAL_MDTAB_CAPACITY;
+ shard->capacity = INITIAL_SHARD_CAPACITY;
shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
}
}
void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) {
- size_t i;
- for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
- mdtab_shard *shard = &g_mdtab_shard[i];
+ for (size_t i = 0; i < SHARD_COUNT; i++) {
+ mdtab_shard *shard = &g_shards[i];
gpr_mu_destroy(&shard->mu);
gc_mdtab(exec_ctx, shard);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
@@ -244,212 +150,35 @@ void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) {
}
gpr_free(shard->elems);
}
- for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
- strtab_shard *shard = &g_strtab_shard[i];
- gpr_mu_destroy(&shard->mu);
- /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
- if (shard->count != 0) {
- gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
- shard->count);
- for (size_t j = 0; j < shard->capacity; j++) {
- for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) {
- gpr_log(GPR_DEBUG, "LEAKED: %s",
- grpc_mdstr_as_c_string((grpc_mdstr *)s));
- }
- }
- if (grpc_iomgr_abort_on_leaks()) {
- abort();
- }
- }
- gpr_free(shard->strs);
- }
}
-static int is_mdstr_static(grpc_mdstr *s) {
- return s >= &grpc_static_mdstr_table[0] &&
- s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
-}
-
-static int is_mdelem_static(grpc_mdelem *e) {
- return e >= &grpc_static_mdelem_table[0] &&
- e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+static int is_mdelem_static(grpc_mdelem e) {
+ return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] &&
+ GRPC_MDELEM_DATA(e) <
+ &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
}
static void ref_md_locked(mdtab_shard *shard,
- internal_metadata *md DEBUG_ARGS) {
+ interned_metadata *md DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
gpr_atm_no_barrier_load(&md->refcnt),
- gpr_atm_no_barrier_load(&md->refcnt) + 1,
- grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
- grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+ gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -1);
}
}
-static void grow_strtab(strtab_shard *shard) {
- size_t capacity = shard->capacity * 2;
- size_t i;
- internal_string **strtab;
- internal_string *s, *next;
-
- GPR_TIMER_BEGIN("grow_strtab", 0);
-
- strtab = gpr_malloc(sizeof(internal_string *) * capacity);
- memset(strtab, 0, sizeof(internal_string *) * capacity);
-
- for (i = 0; i < shard->capacity; i++) {
- for (s = shard->strs[i]; s; s = next) {
- size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
- next = s->bucket_next;
- s->bucket_next = strtab[idx];
- strtab[idx] = s;
- }
- }
-
- gpr_free(shard->strs);
- shard->strs = strtab;
- shard->capacity = capacity;
-
- GPR_TIMER_END("grow_strtab", 0);
-}
-
-static void internal_destroy_string(grpc_exec_ctx *exec_ctx,
- strtab_shard *shard, internal_string *is) {
- internal_string **prev_next;
- internal_string *cur;
- GPR_TIMER_BEGIN("internal_destroy_string", 0);
- if (is->has_base64_and_huffman_encoded) {
- grpc_slice_unref_internal(exec_ctx, is->base64_and_huffman);
- }
- for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
- shard->capacity)],
- cur = *prev_next;
- cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
- ;
- *prev_next = cur->bucket_next;
- shard->count--;
- gpr_free(is);
- GPR_TIMER_END("internal_destroy_string", 0);
-}
-
-static void slice_ref(void *p) {
- internal_string *is =
- (internal_string *)((char *)p - offsetof(internal_string, refcount));
- GRPC_MDSTR_REF((grpc_mdstr *)(is));
-}
-
-static void slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
- internal_string *is =
- (internal_string *)((char *)p - offsetof(internal_string, refcount));
- GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)(is));
-}
-
-grpc_mdstr *grpc_mdstr_from_string(const char *str) {
- return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
-}
-
-grpc_mdstr *grpc_mdstr_from_slice(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
- grpc_mdstr *result = grpc_mdstr_from_buffer(GRPC_SLICE_START_PTR(slice),
- GRPC_SLICE_LENGTH(slice));
- grpc_slice_unref_internal(exec_ctx, slice);
- return result;
-}
-
-grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
- uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed);
- internal_string *s;
- strtab_shard *shard =
- &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
- size_t i;
- size_t idx;
-
- GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
-
- /* search for a static string */
- for (i = 0; i <= g_static_strtab_maxprobe; i++) {
- grpc_mdstr *ss;
- idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
- ss = g_static_strtab[idx];
- if (ss == NULL) break;
- if (ss->hash == hash && GRPC_SLICE_LENGTH(ss->slice) == length &&
- (length == 0 ||
- 0 == memcmp(buf, GRPC_SLICE_START_PTR(ss->slice), length))) {
- GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
- return ss;
- }
- }
-
- gpr_mu_lock(&shard->mu);
-
- /* search for an existing string */
- idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
- for (s = shard->strs[idx]; s; s = s->bucket_next) {
- if (s->hash == hash && GRPC_SLICE_LENGTH(s->slice) == length &&
- 0 == memcmp(buf, GRPC_SLICE_START_PTR(s->slice), length)) {
- if (gpr_atm_full_fetch_add(&s->refcnt, 1) == 0) {
- /* If we get here, we've added a ref to something that was about to
- * die - drop it immediately.
- * The *only* possible path here (given the shard mutex) should be to
- * drop from one ref back to zero - assert that with a CAS */
- GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0));
- /* and treat this as if we were never here... sshhh */
- } else {
- gpr_mu_unlock(&shard->mu);
- GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
- return (grpc_mdstr *)s;
- }
- }
- }
-
- /* not found: create a new string */
- if (length + 1 < GRPC_SLICE_INLINED_SIZE) {
- /* string data goes directly into the slice */
- s = gpr_malloc(sizeof(internal_string));
- gpr_atm_rel_store(&s->refcnt, 1);
- s->slice.refcount = NULL;
- memcpy(s->slice.data.inlined.bytes, buf, length);
- s->slice.data.inlined.bytes[length] = 0;
- s->slice.data.inlined.length = (uint8_t)length;
- } else {
- /* string data goes after the internal_string header, and we +1 for null
- terminator */
- s = gpr_malloc(sizeof(internal_string) + length + 1);
- gpr_atm_rel_store(&s->refcnt, 1);
- s->refcount.ref = slice_ref;
- s->refcount.unref = slice_unref;
- s->slice.refcount = &s->refcount;
- s->slice.data.refcounted.bytes = (uint8_t *)(s + 1);
- s->slice.data.refcounted.length = length;
- memcpy(s->slice.data.refcounted.bytes, buf, length);
- /* add a null terminator for cheap c string conversion when desired */
- s->slice.data.refcounted.bytes[length] = 0;
- }
- s->has_base64_and_huffman_encoded = 0;
- s->hash = hash;
- s->size_in_decoder_table = SIZE_IN_DECODER_TABLE_NOT_SET;
- s->bucket_next = shard->strs[idx];
- shard->strs[idx] = s;
-
- shard->count++;
-
- if (shard->count > shard->capacity * 2) {
- grow_strtab(shard);
- }
-
- gpr_mu_unlock(&shard->mu);
- GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
-
- return (grpc_mdstr *)s;
-}
-
static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
size_t i;
- internal_metadata **prev_next;
- internal_metadata *md, *next;
+ interned_metadata **prev_next;
+ interned_metadata *md, *next;
gpr_atm num_freed = 0;
GPR_TIMER_BEGIN("gc_mdtab", 0);
@@ -459,8 +188,8 @@ static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
next = md->bucket_next;
if (gpr_atm_acq_load(&md->refcnt) == 0) {
- GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->key);
- GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->value);
+ grpc_slice_unref_internal(exec_ctx, md->key);
+ grpc_slice_unref_internal(exec_ctx, md->value);
if (md->user_data) {
((destroy_user_data_func)gpr_atm_no_barrier_load(
&md->destroy_user_data))(user_data);
@@ -481,21 +210,22 @@ static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
static void grow_mdtab(mdtab_shard *shard) {
size_t capacity = shard->capacity * 2;
size_t i;
- internal_metadata **mdtab;
- internal_metadata *md, *next;
+ interned_metadata **mdtab;
+ interned_metadata *md, *next;
uint32_t hash;
GPR_TIMER_BEGIN("grow_mdtab", 0);
- mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
- memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
+ mdtab = gpr_malloc(sizeof(interned_metadata *) * capacity);
+ memset(mdtab, 0, sizeof(interned_metadata *) * capacity);
for (i = 0; i < shard->capacity; i++) {
for (md = shard->elems[i]; md; md = next) {
size_t idx;
- hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+ hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key),
+ grpc_slice_hash(md->value));
next = md->bucket_next;
- idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
+ idx = TABLE_IDX(hash, capacity);
md->bucket_next = mdtab[idx];
mdtab[idx] = md;
}
@@ -517,62 +247,77 @@ static void rehash_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
}
}
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
- grpc_mdstr *mkey,
- grpc_mdstr *mvalue) {
- internal_string *key = (internal_string *)mkey;
- internal_string *value = (internal_string *)mvalue;
- uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
- internal_metadata *md;
- mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
- size_t i;
- size_t idx;
+grpc_mdelem grpc_mdelem_create(
+ grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value,
+ grpc_mdelem_data *compatible_external_backing_store) {
+ if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) {
+ if (compatible_external_backing_store != NULL) {
+ return GRPC_MAKE_MDELEM(compatible_external_backing_store,
+ GRPC_MDELEM_STORAGE_EXTERNAL);
+ }
- GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
+ allocated_metadata *allocated = gpr_malloc(sizeof(*allocated));
+ allocated->key = grpc_slice_ref_internal(key);
+ allocated->value = grpc_slice_ref_internal(value);
+ gpr_atm_rel_store(&allocated->refcnt, 1);
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+ char *key_str = grpc_slice_to_c_string(allocated->key);
+ char *value_str = grpc_slice_to_c_string(allocated->value);
+ gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%zu: '%s' = '%s'", (void *)allocated,
+ gpr_atm_no_barrier_load(&allocated->refcnt), key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
+#endif
+ return GRPC_MAKE_MDELEM(allocated, GRPC_MDELEM_STORAGE_ALLOCATED);
+ }
- if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
- for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
- grpc_mdelem *smd;
- idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
- smd = g_static_mdtab[idx];
- if (smd == NULL) break;
- if (smd->key == mkey && smd->value == mvalue) {
- GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
- return smd;
- }
+ if (GRPC_IS_STATIC_METADATA_STRING(key) &&
+ GRPC_IS_STATIC_METADATA_STRING(value)) {
+ grpc_mdelem static_elem = grpc_static_mdelem_for_static_strings(
+ GRPC_STATIC_METADATA_INDEX(key), GRPC_STATIC_METADATA_INDEX(value));
+ if (!GRPC_MDISNULL(static_elem)) {
+ return static_elem;
}
}
+ uint32_t hash =
+ GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value));
+ interned_metadata *md;
+ mdtab_shard *shard = &g_shards[SHARD_IDX(hash)];
+ size_t idx;
+
+ GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
+
gpr_mu_lock(&shard->mu);
- idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
+ idx = TABLE_IDX(hash, shard->capacity);
/* search for an existing pair */
for (md = shard->elems[idx]; md; md = md->bucket_next) {
- if (md->key == key && md->value == value) {
+ if (grpc_slice_eq(key, md->key) && grpc_slice_eq(value, md->value)) {
REF_MD_LOCKED(shard, md);
- GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)key);
- GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)value);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
- return (grpc_mdelem *)md;
+ return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED);
}
}
/* not found: create a new pair */
- md = gpr_malloc(sizeof(internal_metadata));
+ md = gpr_malloc(sizeof(interned_metadata));
gpr_atm_rel_store(&md->refcnt, 1);
- md->key = key;
- md->value = value;
+ md->key = grpc_slice_ref_internal(key);
+ md->value = grpc_slice_ref_internal(value);
md->user_data = 0;
md->destroy_user_data = 0;
md->bucket_next = shard->elems[idx];
shard->elems[idx] = md;
gpr_mu_init(&md->mu_user_data);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
gpr_log(GPR_DEBUG, "ELM NEW:%p:%zu: '%s' = '%s'", (void *)md,
- gpr_atm_no_barrier_load(&md->refcnt),
- grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
- grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+ gpr_atm_no_barrier_load(&md->refcnt), key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
shard->count++;
@@ -584,29 +329,26 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
- return (grpc_mdelem *)md;
-}
-
-grpc_mdelem *grpc_mdelem_from_strings(grpc_exec_ctx *exec_ctx, const char *key,
- const char *value) {
- return grpc_mdelem_from_metadata_strings(
- exec_ctx, grpc_mdstr_from_string(key), grpc_mdstr_from_string(value));
+ return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED);
}
-grpc_mdelem *grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
- grpc_slice value) {
- return grpc_mdelem_from_metadata_strings(
- exec_ctx, grpc_mdstr_from_slice(exec_ctx, key),
- grpc_mdstr_from_slice(exec_ctx, value));
+grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
+ grpc_slice value) {
+ grpc_mdelem out = grpc_mdelem_create(exec_ctx, key, value, NULL);
+ grpc_slice_unref_internal(exec_ctx, key);
+ grpc_slice_unref_internal(exec_ctx, value);
+ return out;
}
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_exec_ctx *exec_ctx,
- const char *key,
- const uint8_t *value,
- size_t value_length) {
- return grpc_mdelem_from_metadata_strings(
- exec_ctx, grpc_mdstr_from_string(key),
- grpc_mdstr_from_buffer(value, value_length));
+grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_metadata *metadata) {
+ bool changed = false;
+ grpc_slice key_slice =
+ grpc_slice_maybe_static_intern(metadata->key, &changed);
+ grpc_slice value_slice =
+ grpc_slice_maybe_static_intern(metadata->value, &changed);
+ return grpc_mdelem_create(exec_ctx, key_slice, value_slice,
+ changed ? NULL : (grpc_mdelem_data *)metadata);
}
static size_t get_base64_encoded_size(size_t raw_length) {
@@ -614,160 +356,176 @@ static size_t get_base64_encoded_size(size_t raw_length) {
return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
}
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
- size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(elem->key->slice);
- size_t value_len = GRPC_SLICE_LENGTH(elem->value->slice);
- if (is_mdstr_static(elem->value)) {
- if (grpc_is_binary_header(
- (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
- GRPC_SLICE_LENGTH(elem->key->slice))) {
- return overhead_and_key + get_base64_encoded_size(value_len);
- } else {
- return overhead_and_key + value_len;
- }
+size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem) {
+ size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+ size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
+ if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+ return overhead_and_key + get_base64_encoded_size(value_len);
} else {
- internal_string *is = (internal_string *)elem->value;
- gpr_atm current_size = gpr_atm_acq_load(&is->size_in_decoder_table);
- if (current_size == SIZE_IN_DECODER_TABLE_NOT_SET) {
- if (grpc_is_binary_header(
- (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
- GRPC_SLICE_LENGTH(elem->key->slice))) {
- current_size = (gpr_atm)get_base64_encoded_size(value_len);
- } else {
- current_size = (gpr_atm)value_len;
- }
- gpr_atm_rel_store(&is->size_in_decoder_table, current_size);
- }
- return overhead_and_key + (size_t)current_size;
+ return overhead_and_key + value_len;
}
}
-grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
- internal_metadata *md = (internal_metadata *)gmd;
- if (is_mdelem_static(gmd)) return gmd;
+grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) {
+ switch (GRPC_MDELEM_STORAGE(gmd)) {
+ case GRPC_MDELEM_STORAGE_EXTERNAL:
+ case GRPC_MDELEM_STORAGE_STATIC:
+ break;
+ case GRPC_MDELEM_STORAGE_INTERNED: {
+ interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
- gpr_atm_no_barrier_load(&md->refcnt),
- gpr_atm_no_barrier_load(&md->refcnt) + 1,
- grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
- grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
+ gpr_atm_no_barrier_load(&md->refcnt),
+ gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
- /* we can assume the ref count is >= 1 as the application is calling
- this function - meaning that no adjustment to mdtab_free is necessary,
- simplifying the logic here to be just an atomic increment */
- /* use C assert to have this removed in opt builds */
- GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
- gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
- return gmd;
-}
-
-void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *gmd DEBUG_ARGS) {
- internal_metadata *md = (internal_metadata *)gmd;
- if (!md) return;
- if (is_mdelem_static(gmd)) return;
+ /* we can assume the ref count is >= 1 as the application is calling
+ this function - meaning that no adjustment to mdtab_free is necessary,
+ simplifying the logic here to be just an atomic increment */
+ /* use C assert to have this removed in opt builds */
+ GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+ gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
+ break;
+ }
+ case GRPC_MDELEM_STORAGE_ALLOCATED: {
+ allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
- gpr_atm_no_barrier_load(&md->refcnt),
- gpr_atm_no_barrier_load(&md->refcnt) - 1,
- grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
- grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
+ gpr_atm_no_barrier_load(&md->refcnt),
+ gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
- uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
- const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1);
- GPR_ASSERT(prev_refcount >= 1);
- if (1 == prev_refcount) {
- /* once the refcount hits zero, some other thread can come along and
- free md at any time: it's unsafe from this point on to access it */
- mdtab_shard *shard =
- &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
- gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1);
+ /* we can assume the ref count is >= 1 as the application is calling
+ this function - meaning that no adjustment to mdtab_free is necessary,
+ simplifying the logic here to be just an atomic increment */
+ /* use C assert to have this removed in opt builds */
+ gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
+ break;
+ }
}
+ return gmd;
}
-const char *grpc_mdstr_as_c_string(const grpc_mdstr *s) {
- return (const char *)GRPC_SLICE_START_PTR(s->slice);
-}
-
-size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); }
-
-grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
- internal_string *s = (internal_string *)gs;
- if (is_mdstr_static(gs)) return gs;
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem gmd DEBUG_ARGS) {
+ switch (GRPC_MDELEM_STORAGE(gmd)) {
+ case GRPC_MDELEM_STORAGE_EXTERNAL:
+ case GRPC_MDELEM_STORAGE_STATIC:
+ break;
+ case GRPC_MDELEM_STORAGE_INTERNED: {
+ interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%zu->%zu: '%s'",
- (void *)s, gpr_atm_no_barrier_load(&s->refcnt),
- gpr_atm_no_barrier_load(&s->refcnt) + 1, grpc_mdstr_as_c_string(gs));
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
+ gpr_atm_no_barrier_load(&md->refcnt),
+ gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
- GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) > 0);
- return gs;
-}
-
-void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *gs DEBUG_ARGS) {
- internal_string *s = (internal_string *)gs;
- if (is_mdstr_static(gs)) return;
+ uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key),
+ grpc_slice_hash(md->value));
+ const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1);
+ GPR_ASSERT(prev_refcount >= 1);
+ if (1 == prev_refcount) {
+ /* once the refcount hits zero, some other thread can come along and
+ free md at any time: it's unsafe from this point on to access it */
+ mdtab_shard *shard = &g_shards[SHARD_IDX(hash)];
+ gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1);
+ }
+ break;
+ }
+ case GRPC_MDELEM_STORAGE_ALLOCATED: {
+ allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%zu->%zu: '%s'",
- (void *)s, gpr_atm_no_barrier_load(&s->refcnt),
- gpr_atm_no_barrier_load(&s->refcnt) - 1, grpc_mdstr_as_c_string(gs));
+ char *key_str = grpc_slice_to_c_string(md->key);
+ char *value_str = grpc_slice_to_c_string(md->value);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
+ gpr_atm_no_barrier_load(&md->refcnt),
+ gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str);
+ gpr_free(key_str);
+ gpr_free(value_str);
#endif
- if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
- strtab_shard *shard =
- &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
- gpr_mu_lock(&shard->mu);
- GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
- internal_destroy_string(exec_ctx, shard, s);
- gpr_mu_unlock(&shard->mu);
+ const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1);
+ GPR_ASSERT(prev_refcount >= 1);
+ if (1 == prev_refcount) {
+ grpc_slice_unref_internal(exec_ctx, md->key);
+ grpc_slice_unref_internal(exec_ctx, md->value);
+ gpr_free(md);
+ }
+ break;
+ }
}
}
-void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
- internal_metadata *im = (internal_metadata *)md;
- void *result;
- if (is_mdelem_static(md)) {
- return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
- }
- if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
- return (void *)gpr_atm_no_barrier_load(&im->user_data);
- } else {
- return NULL;
+void *grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void *)) {
+ switch (GRPC_MDELEM_STORAGE(md)) {
+ case GRPC_MDELEM_STORAGE_EXTERNAL:
+ case GRPC_MDELEM_STORAGE_ALLOCATED:
+ return NULL;
+ case GRPC_MDELEM_STORAGE_STATIC:
+ return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
+ grpc_static_mdelem_table];
+ case GRPC_MDELEM_STORAGE_INTERNED: {
+ interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md);
+ void *result;
+ if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
+ return (void *)gpr_atm_no_barrier_load(&im->user_data);
+ } else {
+ return NULL;
+ }
+ return result;
+ }
}
- return result;
+ GPR_UNREACHABLE_CODE(return NULL);
}
-void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+void *grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void *),
void *user_data) {
- internal_metadata *im = (internal_metadata *)md;
- GPR_ASSERT(!is_mdelem_static(md));
- GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
- gpr_mu_lock(&im->mu_user_data);
- if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
- /* user data can only be set once */
- gpr_mu_unlock(&im->mu_user_data);
- if (destroy_func != NULL) {
+ switch (GRPC_MDELEM_STORAGE(md)) {
+ case GRPC_MDELEM_STORAGE_EXTERNAL:
+ case GRPC_MDELEM_STORAGE_ALLOCATED:
destroy_func(user_data);
+ return NULL;
+ case GRPC_MDELEM_STORAGE_STATIC:
+ destroy_func(user_data);
+ return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
+ grpc_static_mdelem_table];
+ case GRPC_MDELEM_STORAGE_INTERNED: {
+ interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md);
+ GPR_ASSERT(!is_mdelem_static(md));
+ GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
+ gpr_mu_lock(&im->mu_user_data);
+ if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
+ /* user data can only be set once */
+ gpr_mu_unlock(&im->mu_user_data);
+ if (destroy_func != NULL) {
+ destroy_func(user_data);
+ }
+ return (void *)gpr_atm_no_barrier_load(&im->user_data);
+ }
+ gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
+ gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
+ gpr_mu_unlock(&im->mu_user_data);
+ return user_data;
}
- return (void *)gpr_atm_no_barrier_load(&im->user_data);
}
- gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
- gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
- gpr_mu_unlock(&im->mu_user_data);
- return user_data;
+ GPR_UNREACHABLE_CODE(return NULL);
}
-grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
- internal_string *s = (internal_string *)gs;
- grpc_slice slice;
- strtab_shard *shard =
- &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
- gpr_mu_lock(&shard->mu);
- if (!s->has_base64_and_huffman_encoded) {
- s->base64_and_huffman =
- grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
- s->has_base64_and_huffman_encoded = 1;
- }
- slice = s->base64_and_huffman;
- gpr_mu_unlock(&shard->mu);
- return slice;
+bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b) {
+ if (a.payload == b.payload) return true;
+ if (GRPC_MDELEM_IS_INTERNED(a) && GRPC_MDELEM_IS_INTERNED(b)) return false;
+ if (GRPC_MDISNULL(a) || GRPC_MDISNULL(b)) return false;
+ return grpc_slice_eq(GRPC_MDKEY(a), GRPC_MDKEY(b)) &&
+ grpc_slice_eq(GRPC_MDVALUE(a), GRPC_MDVALUE(b));
}
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 991eee96f1..f4ba86c854 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -34,6 +34,7 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_H
#define GRPC_CORE_LIB_TRANSPORT_METADATA_H
+#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/useful.h>
@@ -74,110 +75,110 @@ extern "C" {
declared here - in which case those functions are effectively no-ops. */
/* Forward declarations */
-typedef struct grpc_mdstr grpc_mdstr;
typedef struct grpc_mdelem grpc_mdelem;
-/* if changing this, make identical changes in internal_string in metadata.c */
-struct grpc_mdstr {
- const grpc_slice slice;
- const uint32_t hash;
+/* if changing this, make identical changes in:
+ - interned_metadata, allocated_metadata in metadata.c
+ - grpc_metadata in grpc_types.h */
+typedef struct grpc_mdelem_data {
+ const grpc_slice key;
+ const grpc_slice value;
/* there is a private part to this in metadata.c */
-};
+} grpc_mdelem_data;
+
+/* GRPC_MDELEM_STORAGE_* enum values that can be treated as interned always have
+ this bit set in their integer value */
+#define GRPC_MDELEM_STORAGE_INTERNED_BIT 1
+
+typedef enum {
+ /* memory pointed to by grpc_mdelem::payload is owned by an external system */
+ GRPC_MDELEM_STORAGE_EXTERNAL = 0,
+ /* memory pointed to by grpc_mdelem::payload is interned by the metadata
+ system */
+ GRPC_MDELEM_STORAGE_INTERNED = GRPC_MDELEM_STORAGE_INTERNED_BIT,
+ /* memory pointed to by grpc_mdelem::payload is allocated by the metadata
+ system */
+ GRPC_MDELEM_STORAGE_ALLOCATED = 2,
+ /* memory is in the static metadata table */
+ GRPC_MDELEM_STORAGE_STATIC = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
+} grpc_mdelem_data_storage;
-/* if changing this, make identical changes in internal_metadata in
- metadata.c */
struct grpc_mdelem {
- grpc_mdstr *const key;
- grpc_mdstr *const value;
- /* there is a private part to this in metadata.c */
+ /* a grpc_mdelem_data* generally, with the two lower bits signalling memory
+ ownership as per grpc_mdelem_data_storage */
+ uintptr_t payload;
};
-void grpc_test_only_set_metadata_hash_seed(uint32_t seed);
-
-/* Constructors for grpc_mdstr instances; take a variety of data types that
- clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(const char *str);
-/* Unrefs the slice. */
-grpc_mdstr *grpc_mdstr_from_slice(grpc_exec_ctx *exec_ctx, grpc_slice slice);
-grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length);
-
-/* Returns a borrowed slice from the mdstr with its contents base64 encoded
- and huffman compressed */
-grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
-
-/* Constructors for grpc_mdelem instances; take a variety of data types that
- clients may have handy */
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
- grpc_mdstr *key,
- grpc_mdstr *value);
-grpc_mdelem *grpc_mdelem_from_strings(grpc_exec_ctx *exec_ctx, const char *key,
- const char *value);
+#define GRPC_MDELEM_DATA(md) \
+ ((grpc_mdelem_data *)((md).payload & ~(uintptr_t)3))
+#define GRPC_MDELEM_STORAGE(md) \
+ ((grpc_mdelem_data_storage)((md).payload & (uintptr_t)3))
+#define GRPC_MAKE_MDELEM(data, storage) \
+ ((grpc_mdelem){((uintptr_t)(data)) | ((uintptr_t)storage)})
+#define GRPC_MDELEM_IS_INTERNED(md) \
+ ((grpc_mdelem_data_storage)((md).payload & \
+ (uintptr_t)GRPC_MDELEM_STORAGE_INTERNED_BIT))
+
/* Unrefs the slices. */
-grpc_mdelem *grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
- grpc_slice value);
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_exec_ctx *exec_ctx,
- const char *key,
- const uint8_t *value,
- size_t value_length);
+grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
+ grpc_slice value);
+
+/* Cheaply convert a grpc_metadata to a grpc_mdelem; may use the grpc_metadata
+ object as backing storage (so lifetimes should align) */
+grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_metadata *metadata);
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem);
+/* Does not unref the slices; if a new non-interned mdelem is needed, allocates
+ one if compatible_external_backing_store is NULL, or uses
+ compatible_external_backing_store if it is non-NULL (in which case it's the
+ users responsibility to ensure that it outlives usage) */
+grpc_mdelem grpc_mdelem_create(
+ grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value,
+ grpc_mdelem_data *compatible_external_backing_store);
+
+bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
+
+size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem);
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
-void *grpc_mdelem_get_user_data(grpc_mdelem *md,
+void *grpc_mdelem_get_user_data(grpc_mdelem md,
void (*if_destroy_func)(void *));
-void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+void *grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void *),
void *user_data);
/* Reference counting */
//#define GRPC_METADATA_REFCOUNT_DEBUG
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
-#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__)
-#define GRPC_MDSTR_UNREF(exec_ctx, s) \
- grpc_mdstr_unref((exec_ctx), (s), __FILE__, __LINE__)
#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__)
#define GRPC_MDELEM_UNREF(exec_ctx, s) \
grpc_mdelem_unref((exec_ctx), (s), __FILE__, __LINE__)
-grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line);
-void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *s, const char *file,
- int line);
-grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line);
-void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *md,
+grpc_mdelem grpc_mdelem_ref(grpc_mdelem md, const char *file, int line);
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem md,
const char *file, int line);
#else
-#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s))
-#define GRPC_MDSTR_UNREF(exec_ctx, s) grpc_mdstr_unref((exec_ctx), (s))
#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s))
#define GRPC_MDELEM_UNREF(exec_ctx, s) grpc_mdelem_unref((exec_ctx), (s))
-grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s);
-void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *s);
-grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md);
-void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *md);
+grpc_mdelem grpc_mdelem_ref(grpc_mdelem md);
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem md);
#endif
-/* Recover a char* from a grpc_mdstr. The returned string is null terminated.
- Does not promise that the returned string has no embedded nulls however. */
-const char *grpc_mdstr_as_c_string(const grpc_mdstr *s);
+#define GRPC_MDKEY(md) (GRPC_MDELEM_DATA(md)->key)
+#define GRPC_MDVALUE(md) (GRPC_MDELEM_DATA(md)->value)
-#define GRPC_MDSTR_LENGTH(s) (GRPC_SLICE_LENGTH(s->slice))
+#define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL)
+#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
/* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */
-#define GRPC_MDELEM_LENGTH(e) \
- (GRPC_MDSTR_LENGTH((e)->key) + GRPC_MDSTR_LENGTH((e)->value) + 32)
-
-int grpc_mdstr_is_legal_header(grpc_mdstr *s);
-int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s);
-int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);
+#define GRPC_MDELEM_LENGTH(e) \
+ (GRPC_SLICE_LENGTH(GRPC_MDKEY((e))) + GRPC_SLICE_LENGTH(GRPC_MDVALUE((e))) + \
+ 32)
#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
void grpc_mdctx_global_init(void);
void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx);
-/* Implementation provided by chttp2_transport */
-extern grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(
- grpc_slice input);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c
index b62ecc3aa6..fc2c52bd8a 100644
--- a/src/core/lib/transport/metadata_batch.c
+++ b/src/core/lib/transport/metadata_batch.c
@@ -40,6 +40,8 @@
#include <grpc/support/log.h>
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
static void assert_valid_list(grpc_mdelem_list *list) {
#ifndef NDEBUG
@@ -51,16 +53,34 @@ static void assert_valid_list(grpc_mdelem_list *list) {
GPR_ASSERT(list->tail->next == NULL);
GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
+ size_t verified_count = 0;
for (l = list->head; l; l = l->next) {
- GPR_ASSERT(l->md);
+ GPR_ASSERT(!GRPC_MDISNULL(l->md));
GPR_ASSERT((l->prev == NULL) == (l == list->head));
GPR_ASSERT((l->next == NULL) == (l == list->tail));
if (l->next) GPR_ASSERT(l->next->prev == l);
if (l->prev) GPR_ASSERT(l->prev->next == l);
+ verified_count++;
}
+ GPR_ASSERT(list->count == verified_count);
#endif /* NDEBUG */
}
+static void assert_valid_callouts(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch) {
+#ifndef NDEBUG
+ for (grpc_linked_mdelem *l = batch->list.head; l != NULL; l = l->next) {
+ grpc_slice key_interned = grpc_slice_intern(GRPC_MDKEY(l->md));
+ grpc_metadata_batch_callouts_index callout_idx =
+ GRPC_BATCH_INDEX_OF(key_interned);
+ if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) {
+ GPR_ASSERT(batch->idx.array[callout_idx] == l);
+ }
+ grpc_slice_unref_internal(exec_ctx, key_interned);
+ }
+#endif
+}
+
#ifndef NDEBUG
void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
assert_valid_list(&batch->list);
@@ -68,7 +88,7 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
#endif /* NDEBUG */
void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
- batch->list.head = batch->list.tail = NULL;
+ memset(batch, 0, sizeof(*batch));
batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
@@ -80,17 +100,58 @@ void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx,
}
}
-void grpc_metadata_batch_add_head(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage,
- grpc_mdelem *elem_to_add) {
- GPR_ASSERT(elem_to_add);
+grpc_error *grpc_attach_md_to_error(grpc_error *src, grpc_mdelem md) {
+ char *k = grpc_slice_to_c_string(GRPC_MDKEY(md));
+ char *v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ grpc_error *out = grpc_error_set_str(
+ grpc_error_set_str(src, GRPC_ERROR_STR_KEY, k), GRPC_ERROR_STR_VALUE, v);
+ gpr_free(k);
+ gpr_free(v);
+ return out;
+}
+
+static grpc_error *maybe_link_callout(grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage)
+ GRPC_MUST_USE_RESULT;
+
+static grpc_error *maybe_link_callout(grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) {
+ grpc_metadata_batch_callouts_index idx =
+ GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
+ if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
+ return GRPC_ERROR_NONE;
+ }
+ if (batch->idx.array[idx] == NULL) {
+ batch->idx.array[idx] = storage;
+ return GRPC_ERROR_NONE;
+ }
+ return grpc_attach_md_to_error(
+ GRPC_ERROR_CREATE("Unallowed duplicate metadata"), storage->md);
+}
+
+static void maybe_unlink_callout(grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) {
+ grpc_metadata_batch_callouts_index idx =
+ GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
+ if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
+ return;
+ }
+ GPR_ASSERT(batch->idx.array[idx] != NULL);
+ batch->idx.array[idx] = NULL;
+}
+
+grpc_error *grpc_metadata_batch_add_head(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem elem_to_add) {
+ GPR_ASSERT(!GRPC_MDISNULL(elem_to_add));
storage->md = elem_to_add;
- grpc_metadata_batch_link_head(batch, storage);
+ return grpc_metadata_batch_link_head(exec_ctx, batch, storage);
}
static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
assert_valid_list(list);
- GPR_ASSERT(storage->md);
+ GPR_ASSERT(!GRPC_MDISNULL(storage->md));
storage->prev = NULL;
storage->next = list->head;
if (list->head != NULL) {
@@ -99,25 +160,36 @@ static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
list->tail = storage;
}
list->head = storage;
+ list->count++;
assert_valid_list(list);
}
-void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage) {
+grpc_error *grpc_metadata_batch_link_head(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) {
+ assert_valid_callouts(exec_ctx, batch);
+ grpc_error *err = maybe_link_callout(batch, storage);
+ if (err != GRPC_ERROR_NONE) {
+ assert_valid_callouts(exec_ctx, batch);
+ return err;
+ }
link_head(&batch->list, storage);
+ assert_valid_callouts(exec_ctx, batch);
+ return GRPC_ERROR_NONE;
}
-void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage,
- grpc_mdelem *elem_to_add) {
- GPR_ASSERT(elem_to_add);
+grpc_error *grpc_metadata_batch_add_tail(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem elem_to_add) {
+ GPR_ASSERT(!GRPC_MDISNULL(elem_to_add));
storage->md = elem_to_add;
- grpc_metadata_batch_link_tail(batch, storage);
+ return grpc_metadata_batch_link_tail(exec_ctx, batch, storage);
}
static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
assert_valid_list(list);
- GPR_ASSERT(storage->md);
+ GPR_ASSERT(!GRPC_MDISNULL(storage->md));
storage->prev = list->tail;
storage->next = NULL;
storage->reserved = NULL;
@@ -127,70 +199,88 @@ static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
list->head = storage;
}
list->tail = storage;
+ list->count++;
assert_valid_list(list);
}
-void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage) {
+grpc_error *grpc_metadata_batch_link_tail(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) {
+ assert_valid_callouts(exec_ctx, batch);
+ grpc_error *err = maybe_link_callout(batch, storage);
+ if (err != GRPC_ERROR_NONE) {
+ assert_valid_callouts(exec_ctx, batch);
+ return err;
+ }
link_tail(&batch->list, storage);
+ assert_valid_callouts(exec_ctx, batch);
+ return GRPC_ERROR_NONE;
}
-void grpc_metadata_batch_move(grpc_metadata_batch *dst,
- grpc_metadata_batch *src) {
- *dst = *src;
- memset(src, 0, sizeof(grpc_metadata_batch));
+static void unlink_storage(grpc_mdelem_list *list,
+ grpc_linked_mdelem *storage) {
+ assert_valid_list(list);
+ if (storage->prev != NULL) {
+ storage->prev->next = storage->next;
+ } else {
+ list->head = storage->next;
+ }
+ if (storage->next != NULL) {
+ storage->next->prev = storage->prev;
+ } else {
+ list->tail = storage->prev;
+ }
+ list->count--;
+ assert_valid_list(list);
}
-void grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx,
+void grpc_metadata_batch_remove(grpc_exec_ctx *exec_ctx,
grpc_metadata_batch *batch,
- grpc_mdelem *(*filter)(grpc_exec_ctx *exec_ctx,
- void *user_data,
- grpc_mdelem *elem),
- void *user_data) {
- grpc_linked_mdelem *l;
- grpc_linked_mdelem *next;
+ grpc_linked_mdelem *storage) {
+ assert_valid_callouts(exec_ctx, batch);
+ maybe_unlink_callout(batch, storage);
+ unlink_storage(&batch->list, storage);
+ GRPC_MDELEM_UNREF(exec_ctx, storage->md);
+ assert_valid_callouts(exec_ctx, batch);
+}
- GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0);
+void grpc_metadata_batch_set_value(grpc_exec_ctx *exec_ctx,
+ grpc_linked_mdelem *storage,
+ grpc_slice value) {
+ grpc_mdelem old = storage->md;
+ grpc_mdelem new = grpc_mdelem_from_slices(
+ exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(old)), value);
+ storage->md = new;
+ GRPC_MDELEM_UNREF(exec_ctx, old);
+}
- assert_valid_list(&batch->list);
- for (l = batch->list.head; l; l = next) {
- grpc_mdelem *orig = l->md;
- grpc_mdelem *filt = filter(exec_ctx, user_data, orig);
- next = l->next;
- if (filt == NULL) {
- if (l->prev) {
- l->prev->next = l->next;
- }
- if (l->next) {
- l->next->prev = l->prev;
- }
- if (batch->list.head == l) {
- batch->list.head = l->next;
- }
- if (batch->list.tail == l) {
- batch->list.tail = l->prev;
- }
- assert_valid_list(&batch->list);
- GRPC_MDELEM_UNREF(exec_ctx, l->md);
- } else if (filt != orig) {
- GRPC_MDELEM_UNREF(exec_ctx, orig);
- l->md = filt;
+grpc_error *grpc_metadata_batch_substitute(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem new) {
+ assert_valid_callouts(exec_ctx, batch);
+ grpc_error *error = GRPC_ERROR_NONE;
+ grpc_mdelem old = storage->md;
+ if (!grpc_slice_eq(GRPC_MDKEY(new), GRPC_MDKEY(old))) {
+ maybe_unlink_callout(batch, storage);
+ storage->md = new;
+ error = maybe_link_callout(batch, storage);
+ if (error != GRPC_ERROR_NONE) {
+ unlink_storage(&batch->list, storage);
+ GRPC_MDELEM_UNREF(exec_ctx, storage->md);
}
+ } else {
+ storage->md = new;
}
- assert_valid_list(&batch->list);
-
- GPR_TIMER_END("grpc_metadata_batch_filter", 0);
-}
-
-static grpc_mdelem *no_metadata_for_you(grpc_exec_ctx *exec_ctx,
- void *user_data, grpc_mdelem *elem) {
- return NULL;
+ GRPC_MDELEM_UNREF(exec_ctx, old);
+ assert_valid_callouts(exec_ctx, batch);
+ return error;
}
void grpc_metadata_batch_clear(grpc_exec_ctx *exec_ctx,
grpc_metadata_batch *batch) {
- batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
- grpc_metadata_batch_filter(exec_ctx, batch, no_metadata_for_you, NULL);
+ grpc_metadata_batch_destroy(exec_ctx, batch);
+ grpc_metadata_batch_init(batch);
}
bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
@@ -207,3 +297,33 @@ size_t grpc_metadata_batch_size(grpc_metadata_batch *batch) {
}
return size;
}
+
+static void add_error(grpc_error **composite, grpc_error *error,
+ const char *composite_error_string) {
+ if (error == GRPC_ERROR_NONE) return;
+ if (*composite == GRPC_ERROR_NONE) {
+ *composite = GRPC_ERROR_CREATE(composite_error_string);
+ }
+ *composite = grpc_error_add_child(*composite, error);
+}
+
+grpc_error *grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_metadata_batch_filter_func func,
+ void *user_data,
+ const char *composite_error_string) {
+ grpc_linked_mdelem *l = batch->list.head;
+ grpc_error *error = GRPC_ERROR_NONE;
+ while (l) {
+ grpc_linked_mdelem *next = l->next;
+ grpc_filtered_mdelem new = func(exec_ctx, user_data, l->md);
+ add_error(&error, new.error, composite_error_string);
+ if (GRPC_MDISNULL(new.md)) {
+ grpc_metadata_batch_remove(exec_ctx, batch, l);
+ } else if (new.md.payload != l->md.payload) {
+ grpc_metadata_batch_substitute(exec_ctx, batch, l, new.md);
+ }
+ l = next;
+ }
+ return error;
+}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index c0bd5174ab..5471539e82 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -41,19 +41,21 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/time.h>
#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/static_metadata.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct grpc_linked_mdelem {
- grpc_mdelem *md;
+ grpc_mdelem md;
struct grpc_linked_mdelem *next;
struct grpc_linked_mdelem *prev;
void *reserved;
} grpc_linked_mdelem;
typedef struct grpc_mdelem_list {
+ size_t count;
grpc_linked_mdelem *head;
grpc_linked_mdelem *tail;
} grpc_mdelem_list;
@@ -61,6 +63,7 @@ typedef struct grpc_mdelem_list {
typedef struct grpc_metadata_batch {
/** Metadata elements in this batch */
grpc_mdelem_list list;
+ grpc_metadata_batch_callouts idx;
/** Used to calculate grpc-timeout at the point of sending,
or gpr_inf_future if this batch does not need to send a
grpc-timeout */
@@ -77,25 +80,37 @@ bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
/* Returns the transport size of the batch. */
size_t grpc_metadata_batch_size(grpc_metadata_batch *batch);
-/** Moves the metadata information from \a src to \a dst. Upon return, \a src is
- * zeroed. */
-void grpc_metadata_batch_move(grpc_metadata_batch *dst,
- grpc_metadata_batch *src);
+/** Remove \a storage from the batch, unreffing the mdelem contained */
+void grpc_metadata_batch_remove(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage);
+
+/** Substitute a new mdelem for an old value */
+grpc_error *grpc_metadata_batch_substitute(grpc_exec_ctx *exec_ctx,
+ grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem new_value);
+
+void grpc_metadata_batch_set_value(grpc_exec_ctx *exec_ctx,
+ grpc_linked_mdelem *storage,
+ grpc_slice value);
/** Add \a storage to the beginning of \a batch. storage->md is
assumed to be valid.
\a storage is owned by the caller and must survive for the
lifetime of batch. This usually means it should be around
for the lifetime of the call. */
-void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage);
+grpc_error *grpc_metadata_batch_link_head(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) GRPC_MUST_USE_RESULT;
/** Add \a storage to the end of \a batch. storage->md is
assumed to be valid.
\a storage is owned by the caller and must survive for the
lifetime of batch. This usually means it should be around
for the lifetime of the call. */
-void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage);
+grpc_error *grpc_metadata_batch_link_tail(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage) GRPC_MUST_USE_RESULT;
/** Add \a elem_to_add as the first element in \a batch, using
\a storage as backing storage for the linked list element.
@@ -103,29 +118,38 @@ void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
lifetime of batch. This usually means it should be around
for the lifetime of the call.
Takes ownership of \a elem_to_add */
-void grpc_metadata_batch_add_head(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage,
- grpc_mdelem *elem_to_add);
+grpc_error *grpc_metadata_batch_add_head(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage, grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
/** Add \a elem_to_add as the last element in \a batch, using
\a storage as backing storage for the linked list element.
\a storage is owned by the caller and must survive for the
lifetime of batch. This usually means it should be around
for the lifetime of the call.
Takes ownership of \a elem_to_add */
-void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch,
- grpc_linked_mdelem *storage,
- grpc_mdelem *elem_to_add);
-
-/** For each element in \a batch, execute \a filter.
- The return value from \a filter will be substituted for the
- grpc_mdelem passed to \a filter. If \a filter returns NULL,
- the element will be moved to the garbage list. */
-void grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx,
- grpc_metadata_batch *batch,
- grpc_mdelem *(*filter)(grpc_exec_ctx *exec_ctx,
- void *user_data,
- grpc_mdelem *elem),
- void *user_data);
+grpc_error *grpc_metadata_batch_add_tail(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch,
+ grpc_linked_mdelem *storage, grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
+
+grpc_error *grpc_attach_md_to_error(grpc_error *src, grpc_mdelem md);
+
+typedef struct {
+ grpc_error *error;
+ grpc_mdelem md;
+} grpc_filtered_mdelem;
+
+#define GRPC_FILTERED_ERROR(error) \
+ ((grpc_filtered_mdelem){(error), GRPC_MDNULL})
+#define GRPC_FILTERED_MDELEM(md) ((grpc_filtered_mdelem){GRPC_ERROR_NONE, (md)})
+#define GRPC_FILTERED_REMOVE() \
+ ((grpc_filtered_mdelem){GRPC_ERROR_NONE, GRPC_MDNULL})
+
+typedef grpc_filtered_mdelem (*grpc_metadata_batch_filter_func)(
+ grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem elem);
+grpc_error *grpc_metadata_batch_filter(
+ grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch,
+ grpc_metadata_batch_filter_func func, void *user_data,
+ const char *composite_error_string) GRPC_MUST_USE_RESULT;
#ifndef NDEBUG
void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd);
diff --git a/src/core/lib/transport/method_config.c b/src/core/lib/transport/method_config.c
deleted file mode 100644
index 25fb54b37d..0000000000
--- a/src/core/lib/transport/method_config.c
+++ /dev/null
@@ -1,347 +0,0 @@
-//
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-
-#include "src/core/lib/transport/method_config.h"
-
-#include <string.h>
-
-#include <grpc/impl/codegen/grpc_types.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/time.h>
-
-#include "src/core/lib/transport/mdstr_hash_table.h"
-#include "src/core/lib/transport/metadata.h"
-
-//
-// grpc_method_config
-//
-
-// bool vtable
-
-static void* bool_copy(void* valuep) {
- bool value = *(bool*)valuep;
- bool* new_value = gpr_malloc(sizeof(bool));
- *new_value = value;
- return new_value;
-}
-
-static int bool_cmp(void* v1, void* v2) {
- bool b1 = *(bool*)v1;
- bool b2 = *(bool*)v2;
- if (!b1 && b2) return -1;
- if (b1 && !b2) return 1;
- return 0;
-}
-
-static void free_mem(grpc_exec_ctx* exec_ctx, void* p) { gpr_free(p); }
-
-static grpc_mdstr_hash_table_vtable bool_vtable = {free_mem, bool_copy,
- bool_cmp};
-
-// timespec vtable
-
-static void* timespec_copy(void* valuep) {
- gpr_timespec value = *(gpr_timespec*)valuep;
- gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
- *new_value = value;
- return new_value;
-}
-
-static int timespec_cmp(void* v1, void* v2) {
- return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
-}
-
-static grpc_mdstr_hash_table_vtable timespec_vtable = {free_mem, timespec_copy,
- timespec_cmp};
-
-// int32 vtable
-
-static void* int32_copy(void* valuep) {
- int32_t value = *(int32_t*)valuep;
- int32_t* new_value = gpr_malloc(sizeof(int32_t));
- *new_value = value;
- return new_value;
-}
-
-static int int32_cmp(void* v1, void* v2) {
- int32_t i1 = *(int32_t*)v1;
- int32_t i2 = *(int32_t*)v2;
- if (i1 < i2) return -1;
- if (i1 > i2) return 1;
- return 0;
-}
-
-static grpc_mdstr_hash_table_vtable int32_vtable = {free_mem, int32_copy,
- int32_cmp};
-
-// Hash table keys.
-#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
-#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
-#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
- "grpc.max_request_message_bytes" // int32
-#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
- "grpc.max_response_message_bytes" // int32
-
-struct grpc_method_config {
- grpc_mdstr_hash_table* table;
- grpc_mdstr* wait_for_ready_key;
- grpc_mdstr* timeout_key;
- grpc_mdstr* max_request_message_bytes_key;
- grpc_mdstr* max_response_message_bytes_key;
-};
-
-grpc_method_config* grpc_method_config_create(
- bool* wait_for_ready, gpr_timespec* timeout,
- int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
- grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
- memset(method_config, 0, sizeof(grpc_method_config));
- method_config->wait_for_ready_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
- method_config->timeout_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
- method_config->max_request_message_bytes_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
- method_config->max_response_message_bytes_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
- grpc_mdstr_hash_table_entry entries[4];
- size_t num_entries = 0;
- if (wait_for_ready != NULL) {
- entries[num_entries].key = method_config->wait_for_ready_key;
- entries[num_entries].value = wait_for_ready;
- entries[num_entries].vtable = &bool_vtable;
- ++num_entries;
- }
- if (timeout != NULL) {
- entries[num_entries].key = method_config->timeout_key;
- entries[num_entries].value = timeout;
- entries[num_entries].vtable = &timespec_vtable;
- ++num_entries;
- }
- if (max_request_message_bytes != NULL) {
- entries[num_entries].key = method_config->max_request_message_bytes_key;
- entries[num_entries].value = max_request_message_bytes;
- entries[num_entries].vtable = &int32_vtable;
- ++num_entries;
- }
- if (max_response_message_bytes != NULL) {
- entries[num_entries].key = method_config->max_response_message_bytes_key;
- entries[num_entries].value = max_response_message_bytes;
- entries[num_entries].vtable = &int32_vtable;
- ++num_entries;
- }
- method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
- return method_config;
-}
-
-grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
- grpc_mdstr_hash_table_ref(method_config->table);
- return method_config;
-}
-
-void grpc_method_config_unref(grpc_exec_ctx* exec_ctx,
- grpc_method_config* method_config) {
- if (grpc_mdstr_hash_table_unref(exec_ctx, method_config->table)) {
- GRPC_MDSTR_UNREF(exec_ctx, method_config->wait_for_ready_key);
- GRPC_MDSTR_UNREF(exec_ctx, method_config->timeout_key);
- GRPC_MDSTR_UNREF(exec_ctx, method_config->max_request_message_bytes_key);
- GRPC_MDSTR_UNREF(exec_ctx, method_config->max_response_message_bytes_key);
- gpr_free(method_config);
- }
-}
-
-int grpc_method_config_cmp(const grpc_method_config* method_config1,
- const grpc_method_config* method_config2) {
- return grpc_mdstr_hash_table_cmp(method_config1->table,
- method_config2->table);
-}
-
-const bool* grpc_method_config_get_wait_for_ready(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(method_config->table,
- method_config->wait_for_ready_key);
-}
-
-const gpr_timespec* grpc_method_config_get_timeout(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(method_config->table,
- method_config->timeout_key);
-}
-
-const int32_t* grpc_method_config_get_max_request_message_bytes(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(
- method_config->table, method_config->max_request_message_bytes_key);
-}
-
-const int32_t* grpc_method_config_get_max_response_message_bytes(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(
- method_config->table, method_config->max_response_message_bytes_key);
-}
-
-//
-// grpc_method_config_table
-//
-
-static void method_config_unref(grpc_exec_ctx* exec_ctx, void* valuep) {
- grpc_method_config_unref(exec_ctx, valuep);
-}
-
-static void* method_config_ref(void* valuep) {
- return grpc_method_config_ref(valuep);
-}
-
-static int method_config_cmp(void* valuep1, void* valuep2) {
- return grpc_method_config_cmp(valuep1, valuep2);
-}
-
-static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
- method_config_unref, method_config_ref, method_config_cmp};
-
-grpc_method_config_table* grpc_method_config_table_create(
- size_t num_entries, grpc_method_config_table_entry* entries) {
- grpc_mdstr_hash_table_entry* hash_table_entries =
- gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
- for (size_t i = 0; i < num_entries; ++i) {
- hash_table_entries[i].key = entries[i].method_name;
- hash_table_entries[i].value = entries[i].method_config;
- hash_table_entries[i].vtable = &method_config_table_vtable;
- }
- grpc_method_config_table* method_config_table =
- grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
- gpr_free(hash_table_entries);
- return method_config_table;
-}
-
-grpc_method_config_table* grpc_method_config_table_ref(
- grpc_method_config_table* table) {
- return grpc_mdstr_hash_table_ref(table);
-}
-
-void grpc_method_config_table_unref(grpc_exec_ctx* exec_ctx,
- grpc_method_config_table* table) {
- grpc_mdstr_hash_table_unref(exec_ctx, table);
-}
-
-int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
- const grpc_method_config_table* table2) {
- return grpc_mdstr_hash_table_cmp(table1, table2);
-}
-
-void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
- const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path) {
- void* value = grpc_mdstr_hash_table_get(table, path);
- // If we didn't find a match for the path, try looking for a wildcard
- // entry (i.e., change "/service/method" to "/service/*").
- if (value == NULL) {
- const char* path_str = grpc_mdstr_as_c_string(path);
- const char* sep = strrchr(path_str, '/') + 1;
- const size_t len = (size_t)(sep - path_str);
- char* buf = gpr_malloc(len + 2); // '*' and NUL
- memcpy(buf, path_str, len);
- buf[len] = '*';
- buf[len + 1] = '\0';
- grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
- gpr_free(buf);
- value = grpc_mdstr_hash_table_get(table, wildcard_path);
- GRPC_MDSTR_UNREF(exec_ctx, wildcard_path);
- }
- return value;
-}
-
-static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
-
-static void destroy_arg(grpc_exec_ctx* exec_ctx, void* p) {
- grpc_method_config_table_unref(exec_ctx, p);
-}
-
-static int cmp_arg(void* p1, void* p2) {
- return grpc_method_config_table_cmp(p1, p2);
-}
-
-static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
-
-grpc_arg grpc_method_config_table_create_channel_arg(
- grpc_method_config_table* table) {
- grpc_arg arg;
- arg.type = GRPC_ARG_POINTER;
- arg.key = GRPC_ARG_SERVICE_CONFIG;
- arg.value.pointer.p = table;
- arg.value.pointer.vtable = &arg_vtable;
- return arg;
-}
-
-// State used by convert_entry() below.
-typedef struct conversion_state {
- void* (*convert_value)(const grpc_method_config* method_config);
- const grpc_mdstr_hash_table_vtable* vtable;
- size_t num_entries;
- grpc_mdstr_hash_table_entry* entries;
-} conversion_state;
-
-// A function to be passed to grpc_mdstr_hash_table_iterate() to create
-// a copy of the entries.
-static void convert_entry(const grpc_mdstr_hash_table_entry* entry,
- void* user_data) {
- conversion_state* state = user_data;
- state->entries[state->num_entries].key = GRPC_MDSTR_REF(entry->key);
- state->entries[state->num_entries].value = state->convert_value(entry->value);
- state->entries[state->num_entries].vtable = state->vtable;
- ++state->num_entries;
-}
-
-grpc_mdstr_hash_table* grpc_method_config_table_convert(
- grpc_exec_ctx* exec_ctx, const grpc_method_config_table* table,
- void* (*convert_value)(const grpc_method_config* method_config),
- const grpc_mdstr_hash_table_vtable* vtable) {
- // Create an array of the entries in the table with converted values.
- conversion_state state;
- state.convert_value = convert_value;
- state.vtable = vtable;
- state.num_entries = 0;
- state.entries = gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) *
- grpc_mdstr_hash_table_num_entries(table));
- grpc_mdstr_hash_table_iterate(table, convert_entry, &state);
- // Create a new table based on the array we just constructed.
- grpc_mdstr_hash_table* new_table =
- grpc_mdstr_hash_table_create(state.num_entries, state.entries);
- // Clean up the array.
- for (size_t i = 0; i < state.num_entries; ++i) {
- GRPC_MDSTR_UNREF(exec_ctx, state.entries[i].key);
- vtable->destroy_value(exec_ctx, state.entries[i].value);
- }
- gpr_free(state.entries);
- // Return the new table.
- return new_table;
-}
diff --git a/src/core/lib/transport/method_config.h b/src/core/lib/transport/method_config.h
deleted file mode 100644
index d17a493fd4..0000000000
--- a/src/core/lib/transport/method_config.h
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// Copyright 2016, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-
-#ifndef GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
-#define GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
-
-#include <stdbool.h>
-
-#include <grpc/impl/codegen/gpr_types.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-#include "src/core/lib/transport/mdstr_hash_table.h"
-#include "src/core/lib/transport/metadata.h"
-
-/// Per-method configuration.
-typedef struct grpc_method_config grpc_method_config;
-
-/// Creates a grpc_method_config with the specified parameters.
-/// Any parameter may be NULL to indicate that the value is unset.
-///
-/// \a wait_for_ready indicates whether the client should wait until the
-/// request deadline for the channel to become ready, even if there is a
-/// temporary failure before the deadline while attempting to connect.
-///
-/// \a timeout indicates the timeout for calls.
-///
-/// \a max_request_message_bytes and \a max_response_message_bytes
-/// indicate the maximum sizes of the request (checked when sending) and
-/// response (checked when receiving) messages.
-grpc_method_config* grpc_method_config_create(
- bool* wait_for_ready, gpr_timespec* timeout,
- int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
-
-grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
-void grpc_method_config_unref(grpc_exec_ctx* exec_ctx,
- grpc_method_config* method_config);
-
-/// Compares two grpc_method_configs.
-/// The sort order is stable but undefined.
-int grpc_method_config_cmp(const grpc_method_config* method_config1,
- const grpc_method_config* method_config2);
-
-/// These methods return NULL if the requested field is unset.
-/// The caller does NOT take ownership of the result.
-const bool* grpc_method_config_get_wait_for_ready(
- const grpc_method_config* method_config);
-const gpr_timespec* grpc_method_config_get_timeout(
- const grpc_method_config* method_config);
-const int32_t* grpc_method_config_get_max_request_message_bytes(
- const grpc_method_config* method_config);
-const int32_t* grpc_method_config_get_max_response_message_bytes(
- const grpc_method_config* method_config);
-
-/// A table of method configs.
-typedef grpc_mdstr_hash_table grpc_method_config_table;
-
-typedef struct grpc_method_config_table_entry {
- /// The name is of one of the following forms:
- /// service/method -- specifies exact service and method name
- /// service/* -- matches all methods for the specified service
- grpc_mdstr* method_name;
- grpc_method_config* method_config;
-} grpc_method_config_table_entry;
-
-/// Takes new references to all keys and values in \a entries.
-grpc_method_config_table* grpc_method_config_table_create(
- size_t num_entries, grpc_method_config_table_entry* entries);
-
-grpc_method_config_table* grpc_method_config_table_ref(
- grpc_method_config_table* table);
-void grpc_method_config_table_unref(grpc_exec_ctx* exec_ctx,
- grpc_method_config_table* table);
-
-/// Compares two grpc_method_config_tables.
-/// The sort order is stable but undefined.
-int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
- const grpc_method_config_table* table2);
-
-/// Gets the method config for the specified \a path, which should be of
-/// the form "/service/method".
-/// Returns NULL if the method has no config.
-/// Caller does NOT own a reference to the result.
-///
-/// Note: This returns a void* instead of a grpc_method_config* so that
-/// it can also be used for tables constructed via
-/// grpc_method_config_table_convert().
-void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
- const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path);
-
-/// Returns a channel arg containing \a table.
-grpc_arg grpc_method_config_table_create_channel_arg(
- grpc_method_config_table* table);
-
-/// Generates a new table from \a table whose values are converted to a
-/// new form via the \a convert_value function. The new table will use
-/// \a vtable for its values.
-///
-/// This is generally used to convert the table's value type from
-/// grpc_method_config to a simple struct containing only the parameters
-/// relevant to a particular filter, thus avoiding the need for a hash
-/// table lookup on the fast path. In that scenario, \a convert_value
-/// will return a new instance of the struct containing the values from
-/// the grpc_method_config, and \a vtable provides the methods for
-/// operating on the struct type.
-grpc_mdstr_hash_table* grpc_method_config_table_convert(
- grpc_exec_ctx* exec_ctx, const grpc_method_config_table* table,
- void* (*convert_value)(const grpc_method_config* method_config),
- const grpc_mdstr_hash_table_vtable* vtable);
-
-#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */
diff --git a/src/core/lib/transport/pid_controller.c b/src/core/lib/transport/pid_controller.c
index 3cef225d4b..19cb1c0b36 100644
--- a/src/core/lib/transport/pid_controller.c
+++ b/src/core/lib/transport/pid_controller.c
@@ -32,26 +32,46 @@
*/
#include "src/core/lib/transport/pid_controller.h"
+#include <grpc/support/useful.h>
void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
- double gain_p, double gain_i, double gain_d) {
- pid_controller->gain_p = gain_p;
- pid_controller->gain_i = gain_i;
- pid_controller->gain_d = gain_d;
+ grpc_pid_controller_args args) {
+ pid_controller->args = args;
+ pid_controller->last_control_value = args.initial_control_value;
grpc_pid_controller_reset(pid_controller);
}
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) {
pid_controller->last_error = 0.0;
+ pid_controller->last_dc_dt = 0.0;
pid_controller->error_integral = 0.0;
}
double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
double error, double dt) {
- pid_controller->error_integral += error * dt;
+ /* integrate error using the trapezoid rule */
+ pid_controller->error_integral +=
+ dt * (pid_controller->last_error + error) * 0.5;
+ pid_controller->error_integral = GPR_CLAMP(
+ pid_controller->error_integral, -pid_controller->args.integral_range,
+ pid_controller->args.integral_range);
double diff_error = (error - pid_controller->last_error) / dt;
+ /* calculate derivative of control value vs time */
+ double dc_dt = pid_controller->args.gain_p * error +
+ pid_controller->args.gain_i * pid_controller->error_integral +
+ pid_controller->args.gain_d * diff_error;
+ /* and perform trapezoidal integration */
+ double new_control_value = pid_controller->last_control_value +
+ dt * (pid_controller->last_dc_dt + dc_dt) * 0.5;
+ new_control_value =
+ GPR_CLAMP(new_control_value, pid_controller->args.min_control_value,
+ pid_controller->args.max_control_value);
pid_controller->last_error = error;
- return dt * (pid_controller->gain_p * error +
- pid_controller->gain_i * pid_controller->error_integral +
- pid_controller->gain_d * diff_error);
+ pid_controller->last_dc_dt = dc_dt;
+ pid_controller->last_control_value = new_control_value;
+ return new_control_value;
+}
+
+double grpc_pid_controller_last(grpc_pid_controller *pid_controller) {
+ return pid_controller->last_control_value;
}
diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h
index 83c82d6471..0a86521e90 100644
--- a/src/core/lib/transport/pid_controller.h
+++ b/src/core/lib/transport/pid_controller.h
@@ -45,20 +45,33 @@ typedef struct {
double gain_p;
double gain_i;
double gain_d;
+ double initial_control_value;
+ double min_control_value;
+ double max_control_value;
+ double integral_range;
+} grpc_pid_controller_args;
+
+typedef struct {
double last_error;
double error_integral;
+ double last_control_value;
+ double last_dc_dt;
+ grpc_pid_controller_args args;
} grpc_pid_controller;
/** Initialize the controller */
void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
- double gain_p, double gain_i, double gain_d);
+ grpc_pid_controller_args args);
/** Reset the controller: useful when things have changed significantly */
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller);
/** Update the controller: given a current error estimate, and the time since
- the last update, returns a delta to the control value */
+ the last update, returns a new control value */
double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
double error, double dt);
+/** Returns the last control value calculated */
+double grpc_pid_controller_last(grpc_pid_controller *pid_controller);
+
#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */
diff --git a/src/core/lib/transport/service_config.c b/src/core/lib/transport/service_config.c
index 552d3ec856..12da2a88fe 100644
--- a/src/core/lib/transport/service_config.c
+++ b/src/core/lib/transport/service_config.c
@@ -39,8 +39,10 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/json/json.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/transport/mdstr_hash_table.h"
// The main purpose of the code here is to parse the service config in
// JSON form, which will look like this:
@@ -148,8 +150,8 @@ static char* parse_json_method_name(grpc_json* json) {
static bool parse_json_method_config(
grpc_exec_ctx* exec_ctx, grpc_json* json,
void* (*create_value)(const grpc_json* method_config_json),
- const grpc_mdstr_hash_table_vtable* vtable,
- grpc_mdstr_hash_table_entry* entries, size_t* idx) {
+ const grpc_slice_hash_table_vtable* vtable,
+ grpc_slice_hash_table_entry* entries, size_t* idx) {
// Construct value.
void* method_config = create_value(json);
if (method_config == NULL) return false;
@@ -170,7 +172,7 @@ static bool parse_json_method_config(
if (paths.count == 0) goto done; // No names specified.
// Add entry for each path.
for (size_t i = 0; i < paths.count; ++i) {
- entries[*idx].key = grpc_mdstr_from_string(paths.strs[i]);
+ entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
entries[*idx].value = vtable->copy_value(method_config);
entries[*idx].vtable = vtable;
++*idx;
@@ -182,15 +184,15 @@ done:
return success;
}
-grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
+grpc_slice_hash_table* grpc_service_config_create_method_config_table(
grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
- const grpc_mdstr_hash_table_vtable* vtable) {
+ const grpc_slice_hash_table_vtable* vtable) {
const grpc_json* json = service_config->json_tree;
// Traverse parsed JSON tree.
if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
size_t num_entries = 0;
- grpc_mdstr_hash_table_entry* entries = NULL;
+ grpc_slice_hash_table_entry* entries = NULL;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
if (field->key == NULL) return NULL;
if (strcmp(field->key, "methodConfig") == 0) {
@@ -202,7 +204,7 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
num_entries += count_names_in_method_config_json(method);
}
// Populate method config table entries.
- entries = gpr_malloc(num_entries * sizeof(grpc_mdstr_hash_table_entry));
+ entries = gpr_malloc(num_entries * sizeof(grpc_slice_hash_table_entry));
size_t idx = 0;
for (grpc_json* method = field->child; method != NULL;
method = method->next) {
@@ -215,12 +217,12 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
}
}
// Instantiate method config table.
- grpc_mdstr_hash_table* method_config_table = NULL;
+ grpc_slice_hash_table* method_config_table = NULL;
if (entries != NULL) {
- method_config_table = grpc_mdstr_hash_table_create(num_entries, entries);
+ method_config_table = grpc_slice_hash_table_create(num_entries, entries);
// Clean up.
for (size_t i = 0; i < num_entries; ++i) {
- GRPC_MDSTR_UNREF(exec_ctx, entries[i].key);
+ grpc_slice_unref_internal(exec_ctx, entries[i].key);
vtable->destroy_value(exec_ctx, entries[i].value);
}
gpr_free(entries);
@@ -229,23 +231,24 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
}
void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
- const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path) {
- void* value = grpc_mdstr_hash_table_get(table, path);
+ const grpc_slice_hash_table* table,
+ grpc_slice path) {
+ void* value = grpc_slice_hash_table_get(table, path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (value == NULL) {
- const char* path_str = grpc_mdstr_as_c_string(path);
+ char* path_str = grpc_slice_to_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = (size_t)(sep - path_str);
char* buf = gpr_malloc(len + 2); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
- grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
+ grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
gpr_free(buf);
- value = grpc_mdstr_hash_table_get(table, wildcard_path);
- GRPC_MDSTR_UNREF(exec_ctx, wildcard_path);
+ value = grpc_slice_hash_table_get(table, wildcard_path);
+ grpc_slice_unref_internal(exec_ctx, wildcard_path);
+ gpr_free(path_str);
}
return value;
}
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index f0897170fa..cd739a593c 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -35,7 +35,7 @@
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/json/json.h"
-#include "src/core/lib/transport/mdstr_hash_table.h"
+#include "src/core/lib/slice/slice_hash_table.h"
typedef struct grpc_service_config grpc_service_config;
@@ -53,10 +53,10 @@ const char* grpc_service_config_get_lb_policy_name(
/// returned by \a create_value(), based on data parsed from the JSON tree.
/// \a vtable provides methods used to manage the values.
/// Returns NULL on error.
-grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
+grpc_slice_hash_table* grpc_service_config_create_method_config_table(
grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
- const grpc_mdstr_hash_table_vtable* vtable);
+ const grpc_slice_hash_table_vtable* vtable);
/// A helper function for looking up values in the table returned by
/// \a grpc_service_config_create_method_config_table().
@@ -65,7 +65,7 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
/// Returns NULL if the method has no config.
/// Caller does NOT own a reference to the result.
void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
- const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path);
+ const grpc_slice_hash_table* table,
+ grpc_slice path);
#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index 8b22592b45..750711befd 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -41,120 +41,770 @@
#include "src/core/lib/transport/static_metadata.h"
-grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+#include "src/core/lib/slice/slice_internal.h"
+
+static uint8_t g_bytes[] = {
+ 58, 112, 97, 116, 104, 58, 109, 101, 116, 104, 111, 100, 58, 115, 116,
+ 97, 116, 117, 115, 58, 97, 117, 116, 104, 111, 114, 105, 116, 121, 58,
+ 115, 99, 104, 101, 109, 101, 116, 101, 103, 114, 112, 99, 45, 109, 101,
+ 115, 115, 97, 103, 101, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117,
+ 115, 103, 114, 112, 99, 45, 112, 97, 121, 108, 111, 97, 100, 45, 98,
+ 105, 110, 103, 114, 112, 99, 45, 101, 110, 99, 111, 100, 105, 110, 103,
+ 103, 114, 112, 99, 45, 97, 99, 99, 101, 112, 116, 45, 101, 110, 99,
+ 111, 100, 105, 110, 103, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121,
+ 112, 101, 103, 114, 112, 99, 45, 105, 110, 116, 101, 114, 110, 97, 108,
+ 45, 101, 110, 99, 111, 100, 105, 110, 103, 45, 114, 101, 113, 117, 101,
+ 115, 116, 117, 115, 101, 114, 45, 97, 103, 101, 110, 116, 104, 111, 115,
+ 116, 108, 98, 45, 116, 111, 107, 101, 110, 108, 98, 45, 99, 111, 115,
+ 116, 45, 98, 105, 110, 103, 114, 112, 99, 45, 116, 105, 109, 101, 111,
+ 117, 116, 103, 114, 112, 99, 45, 116, 114, 97, 99, 105, 110, 103, 45,
+ 98, 105, 110, 103, 114, 112, 99, 45, 115, 116, 97, 116, 115, 45, 98,
+ 105, 110, 103, 114, 112, 99, 46, 119, 97, 105, 116, 95, 102, 111, 114,
+ 95, 114, 101, 97, 100, 121, 103, 114, 112, 99, 46, 116, 105, 109, 101,
+ 111, 117, 116, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 113,
+ 117, 101, 115, 116, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98, 121,
+ 116, 101, 115, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 115,
+ 112, 111, 110, 115, 101, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98,
+ 121, 116, 101, 115, 47, 103, 114, 112, 99, 46, 108, 98, 46, 118, 49,
+ 46, 76, 111, 97, 100, 66, 97, 108, 97, 110, 99, 101, 114, 47, 66,
+ 97, 108, 97, 110, 99, 101, 76, 111, 97, 100, 48, 49, 50, 105, 100,
+ 101, 110, 116, 105, 116, 121, 103, 122, 105, 112, 100, 101, 102, 108, 97,
+ 116, 101, 116, 114, 97, 105, 108, 101, 114, 115, 97, 112, 112, 108, 105,
+ 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99, 80, 79, 83, 84,
+ 50, 48, 48, 52, 48, 52, 104, 116, 116, 112, 104, 116, 116, 112, 115,
+ 103, 114, 112, 99, 71, 69, 84, 80, 85, 84, 47, 47, 105, 110, 100,
+ 101, 120, 46, 104, 116, 109, 108, 50, 48, 52, 50, 48, 54, 51, 48,
+ 52, 52, 48, 48, 53, 48, 48, 97, 99, 99, 101, 112, 116, 45, 99,
+ 104, 97, 114, 115, 101, 116, 97, 99, 99, 101, 112, 116, 45, 101, 110,
+ 99, 111, 100, 105, 110, 103, 103, 122, 105, 112, 44, 32, 100, 101, 102,
+ 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45, 108, 97, 110, 103,
+ 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45, 114, 97, 110, 103,
+ 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99, 101, 115, 115, 45,
+ 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108, 111, 119, 45, 111,
+ 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108, 111, 119, 97, 117,
+ 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 99, 97, 99, 104,
+ 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111, 110, 116, 101, 110,
+ 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99, 111,
+ 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 99,
+ 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
+ 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 99,
+ 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116, 105, 111, 110,
+ 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103, 101, 99, 111,
+ 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103, 101, 120, 112,
+ 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105,
+ 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111, 100, 105, 102,
+ 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45, 110, 111, 110,
+ 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97, 110, 103, 101,
+ 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
+ 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100, 105, 102, 105,
+ 101, 100, 108, 105, 110, 107, 108, 111, 99, 97, 116, 105, 111, 110, 109,
+ 97, 120, 45, 102, 111, 114, 119, 97, 114, 100, 115, 112, 114, 111, 120,
+ 121, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 112,
+ 114, 111, 120, 121, 45, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116,
+ 105, 111, 110, 114, 97, 110, 103, 101, 114, 101, 102, 101, 114, 101, 114,
+ 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121, 45, 97, 102,
+ 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116, 45, 99, 111,
+ 111, 107, 105, 101, 115, 116, 114, 105, 99, 116, 45, 116, 114, 97, 110,
+ 115, 112, 111, 114, 116, 45, 115, 101, 99, 117, 114, 105, 116, 121, 116,
+ 114, 97, 110, 115, 102, 101, 114, 45, 101, 110, 99, 111, 100, 105, 110,
+ 103, 118, 97, 114, 121, 118, 105, 97, 119, 119, 119, 45, 97, 117, 116,
+ 104, 101, 110, 116, 105, 99, 97, 116, 101, 105, 100, 101, 110, 116, 105,
+ 116, 121, 44, 100, 101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116,
+ 105, 116, 121, 44, 103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101,
+ 44, 103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100,
+ 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112};
+
+static void static_ref(void *unused) {}
+static void static_unref(grpc_exec_ctx *exec_ctx, void *unused) {}
+static const grpc_slice_refcount_vtable static_sub_vtable = {
+ static_ref, static_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+const grpc_slice_refcount_vtable grpc_static_metadata_vtable = {
+ static_ref, static_unref, grpc_static_slice_eq, grpc_static_slice_hash};
+static grpc_slice_refcount static_sub_refcnt = {&static_sub_vtable,
+ &static_sub_refcnt};
+grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+};
+
+const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
+ {.refcount = &grpc_static_metadata_refcounts[0],
+ .data.refcounted = {g_bytes + 0, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[1],
+ .data.refcounted = {g_bytes + 5, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[3],
+ .data.refcounted = {g_bytes + 19, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[4],
+ .data.refcounted = {g_bytes + 29, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[5],
+ .data.refcounted = {g_bytes + 36, 2}},
+ {.refcount = &grpc_static_metadata_refcounts[6],
+ .data.refcounted = {g_bytes + 38, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[7],
+ .data.refcounted = {g_bytes + 50, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[8],
+ .data.refcounted = {g_bytes + 61, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[9],
+ .data.refcounted = {g_bytes + 77, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[11],
+ .data.refcounted = {g_bytes + 110, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[12],
+ .data.refcounted = {g_bytes + 122, 30}},
+ {.refcount = &grpc_static_metadata_refcounts[13],
+ .data.refcounted = {g_bytes + 152, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[14],
+ .data.refcounted = {g_bytes + 162, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[15],
+ .data.refcounted = {g_bytes + 166, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[16],
+ .data.refcounted = {g_bytes + 174, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[17],
+ .data.refcounted = {g_bytes + 185, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[18],
+ .data.refcounted = {g_bytes + 197, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[19],
+ .data.refcounted = {g_bytes + 213, 14}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}},
+ {.refcount = &grpc_static_metadata_refcounts[21],
+ .data.refcounted = {g_bytes + 227, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[22],
+ .data.refcounted = {g_bytes + 246, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[23],
+ .data.refcounted = {g_bytes + 258, 30}},
+ {.refcount = &grpc_static_metadata_refcounts[24],
+ .data.refcounted = {g_bytes + 288, 31}},
+ {.refcount = &grpc_static_metadata_refcounts[25],
+ .data.refcounted = {g_bytes + 319, 36}},
+ {.refcount = &grpc_static_metadata_refcounts[26],
+ .data.refcounted = {g_bytes + 355, 1}},
+ {.refcount = &grpc_static_metadata_refcounts[27],
+ .data.refcounted = {g_bytes + 356, 1}},
+ {.refcount = &grpc_static_metadata_refcounts[28],
+ .data.refcounted = {g_bytes + 357, 1}},
+ {.refcount = &grpc_static_metadata_refcounts[29],
+ .data.refcounted = {g_bytes + 358, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[30],
+ .data.refcounted = {g_bytes + 366, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[31],
+ .data.refcounted = {g_bytes + 370, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[32],
+ .data.refcounted = {g_bytes + 377, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[33],
+ .data.refcounted = {g_bytes + 385, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[34],
+ .data.refcounted = {g_bytes + 401, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[35],
+ .data.refcounted = {g_bytes + 405, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[36],
+ .data.refcounted = {g_bytes + 408, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[37],
+ .data.refcounted = {g_bytes + 411, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[38],
+ .data.refcounted = {g_bytes + 415, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[39],
+ .data.refcounted = {g_bytes + 420, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[40],
+ .data.refcounted = {g_bytes + 424, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[41],
+ .data.refcounted = {g_bytes + 427, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[42],
+ .data.refcounted = {g_bytes + 430, 1}},
+ {.refcount = &grpc_static_metadata_refcounts[43],
+ .data.refcounted = {g_bytes + 431, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[44],
+ .data.refcounted = {g_bytes + 442, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[45],
+ .data.refcounted = {g_bytes + 445, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[46],
+ .data.refcounted = {g_bytes + 448, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[47],
+ .data.refcounted = {g_bytes + 451, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[48],
+ .data.refcounted = {g_bytes + 454, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[49],
+ .data.refcounted = {g_bytes + 457, 14}},
+ {.refcount = &grpc_static_metadata_refcounts[50],
+ .data.refcounted = {g_bytes + 471, 15}},
+ {.refcount = &grpc_static_metadata_refcounts[51],
+ .data.refcounted = {g_bytes + 486, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[52],
+ .data.refcounted = {g_bytes + 499, 15}},
+ {.refcount = &grpc_static_metadata_refcounts[53],
+ .data.refcounted = {g_bytes + 514, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[54],
+ .data.refcounted = {g_bytes + 527, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[55],
+ .data.refcounted = {g_bytes + 533, 27}},
+ {.refcount = &grpc_static_metadata_refcounts[56],
+ .data.refcounted = {g_bytes + 560, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[57],
+ .data.refcounted = {g_bytes + 563, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[58],
+ .data.refcounted = {g_bytes + 568, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[59],
+ .data.refcounted = {g_bytes + 581, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[60],
+ .data.refcounted = {g_bytes + 594, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[61],
+ .data.refcounted = {g_bytes + 613, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[62],
+ .data.refcounted = {g_bytes + 629, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[63],
+ .data.refcounted = {g_bytes + 645, 14}},
+ {.refcount = &grpc_static_metadata_refcounts[64],
+ .data.refcounted = {g_bytes + 659, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[65],
+ .data.refcounted = {g_bytes + 675, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[66],
+ .data.refcounted = {g_bytes + 688, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[67],
+ .data.refcounted = {g_bytes + 694, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[68],
+ .data.refcounted = {g_bytes + 698, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[69],
+ .data.refcounted = {g_bytes + 702, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[70],
+ .data.refcounted = {g_bytes + 708, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[71],
+ .data.refcounted = {g_bytes + 715, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[72],
+ .data.refcounted = {g_bytes + 719, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[73],
+ .data.refcounted = {g_bytes + 727, 17}},
+ {.refcount = &grpc_static_metadata_refcounts[74],
+ .data.refcounted = {g_bytes + 744, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[75],
+ .data.refcounted = {g_bytes + 757, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[76],
+ .data.refcounted = {g_bytes + 765, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[77],
+ .data.refcounted = {g_bytes + 784, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[78],
+ .data.refcounted = {g_bytes + 797, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[79],
+ .data.refcounted = {g_bytes + 801, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[80],
+ .data.refcounted = {g_bytes + 809, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[81],
+ .data.refcounted = {g_bytes + 821, 18}},
+ {.refcount = &grpc_static_metadata_refcounts[82],
+ .data.refcounted = {g_bytes + 839, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[83],
+ .data.refcounted = {g_bytes + 858, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[84],
+ .data.refcounted = {g_bytes + 863, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[85],
+ .data.refcounted = {g_bytes + 870, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[86],
+ .data.refcounted = {g_bytes + 877, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[87],
+ .data.refcounted = {g_bytes + 888, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[88],
+ .data.refcounted = {g_bytes + 894, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[89],
+ .data.refcounted = {g_bytes + 904, 25}},
+ {.refcount = &grpc_static_metadata_refcounts[90],
+ .data.refcounted = {g_bytes + 929, 17}},
+ {.refcount = &grpc_static_metadata_refcounts[91],
+ .data.refcounted = {g_bytes + 946, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[92],
+ .data.refcounted = {g_bytes + 950, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[93],
+ .data.refcounted = {g_bytes + 953, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[94],
+ .data.refcounted = {g_bytes + 969, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[95],
+ .data.refcounted = {g_bytes + 985, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[96],
+ .data.refcounted = {g_bytes + 998, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[97],
+ .data.refcounted = {g_bytes + 1010, 21}},
+};
-grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8};
+
+static const int8_t elems_r[] = {
+ 10, 8, -3, 0, 9, 21, -76, 22, 0, 10, -7, 20, 0, 19, 18, 17,
+ 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -49, -50, 16, -52, -53, -54, -54, -55, -56, -57, 0, 38, 37, 36, 35,
+ 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
+ 18, 17, 16, 15, 14, 13, 12, 15, 14, 13, 12, 11, 10, 9, 8, 0};
+static uint32_t elems_phash(uint32_t i) {
+ i -= 42;
+ uint32_t x = i % 96;
+ uint32_t y = i / 96;
+ uint32_t h = x;
+ if (y < GPR_ARRAY_SIZE(elems_r)) {
+ uint32_t delta = (uint32_t)elems_r[y];
+ h += delta;
+ }
+ return h;
+}
-const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
- {11, 33, 10, 33, 12, 33, 12, 50, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
- 19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
- 28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
- 40, 32, 40, 49, 40, 54, 40, 55, 40, 56, 40, 57, 41, 31, 41, 49, 41, 54,
- 46, 0, 46, 1, 46, 2, 51, 33, 58, 33, 59, 33, 60, 33, 61, 33, 62, 33,
- 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 33, 69, 38, 69, 71, 69, 74,
- 70, 82, 70, 83, 72, 33, 73, 33, 75, 33, 76, 33, 77, 33, 78, 33, 79, 39,
- 79, 52, 79, 53, 80, 33, 81, 33, 84, 3, 84, 4, 84, 5, 84, 6, 84, 7,
- 84, 8, 84, 9, 85, 33, 86, 87, 88, 33, 89, 33, 90, 33, 91, 33, 92, 33};
+static const uint16_t elem_keys[] = {
+ 1009, 1010, 1011, 240, 241, 242, 243, 244, 138, 139, 42, 43,
+ 429, 430, 431, 911, 912, 913, 712, 713, 1098, 522, 714, 1294,
+ 1392, 1490, 1588, 4822, 4920, 4951, 5116, 5214, 5312, 1111, 5410, 5508,
+ 5606, 5704, 5802, 5900, 5998, 6096, 6194, 6292, 6390, 6488, 6586, 6684,
+ 6782, 6880, 6978, 7076, 7174, 7272, 7370, 7468, 7566, 7664, 7762, 7860,
+ 7958, 8056, 8154, 8252, 8350, 1074, 1075, 1076, 1077, 8448, 8546, 8644,
+ 8742, 8840, 8938, 9036, 9134, 314, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 132, 231, 232, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0};
+static const uint8_t elem_idxs[] = {
+ 74, 77, 75, 19, 20, 21, 22, 23, 15, 16, 17, 18, 11, 12, 13,
+ 3, 4, 5, 0, 1, 41, 6, 2, 70, 48, 55, 56, 24, 25, 26,
+ 27, 28, 29, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 42, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 57, 58, 59,
+ 60, 61, 62, 63, 64, 76, 78, 79, 80, 65, 66, 67, 68, 69, 71,
+ 72, 73, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 9, 10};
-const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
- "0",
- "1",
- "2",
- "200",
- "204",
- "206",
- "304",
- "400",
- "404",
- "500",
- "accept",
- "accept-charset",
- "accept-encoding",
- "accept-language",
- "accept-ranges",
- "access-control-allow-origin",
- "age",
- "allow",
- "application/grpc",
- ":authority",
- "authorization",
- "cache-control",
- "content-disposition",
- "content-encoding",
- "content-language",
- "content-length",
- "content-location",
- "content-range",
- "content-type",
- "cookie",
- "date",
- "deflate",
- "deflate,gzip",
- "",
- "etag",
- "expect",
- "expires",
- "from",
- "GET",
- "grpc",
- "grpc-accept-encoding",
- "grpc-encoding",
- "grpc-internal-encoding-request",
- "grpc-message",
- "grpc-payload-bin",
- "grpc-stats-bin",
- "grpc-status",
- "grpc-timeout",
- "grpc-tracing-bin",
- "gzip",
- "gzip, deflate",
- "host",
- "http",
- "https",
- "identity",
- "identity,deflate",
- "identity,deflate,gzip",
- "identity,gzip",
- "if-match",
- "if-modified-since",
- "if-none-match",
- "if-range",
- "if-unmodified-since",
- "last-modified",
- "lb-cost-bin",
- "lb-token",
- "link",
- "location",
- "max-forwards",
- ":method",
- ":path",
- "POST",
- "proxy-authenticate",
- "proxy-authorization",
- "PUT",
- "range",
- "referer",
- "refresh",
- "retry-after",
- ":scheme",
- "server",
- "set-cookie",
- "/",
- "/index.html",
- ":status",
- "strict-transport-security",
- "te",
- "trailers",
- "transfer-encoding",
- "user-agent",
- "vary",
- "via",
- "www-authenticate"};
+grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
+ if (a == -1 || b == -1) return GRPC_MDNULL;
+ uint32_t k = (uint32_t)(a * 98 + b);
+ uint32_t h = elems_phash(k);
+ return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k
+ ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]],
+ GRPC_MDELEM_STORAGE_STATIC)
+ : GRPC_MDNULL;
+}
-const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30,
- 28, 32, 27, 31};
+grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
+ {{.refcount = &grpc_static_metadata_refcounts[7],
+ .data.refcounted = {g_bytes + 50, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[26],
+ .data.refcounted = {g_bytes + 355, 1}}},
+ {{.refcount = &grpc_static_metadata_refcounts[7],
+ .data.refcounted = {g_bytes + 50, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[27],
+ .data.refcounted = {g_bytes + 356, 1}}},
+ {{.refcount = &grpc_static_metadata_refcounts[7],
+ .data.refcounted = {g_bytes + 50, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[28],
+ .data.refcounted = {g_bytes + 357, 1}}},
+ {{.refcount = &grpc_static_metadata_refcounts[9],
+ .data.refcounted = {g_bytes + 77, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[29],
+ .data.refcounted = {g_bytes + 358, 8}}},
+ {{.refcount = &grpc_static_metadata_refcounts[9],
+ .data.refcounted = {g_bytes + 77, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[30],
+ .data.refcounted = {g_bytes + 366, 4}}},
+ {{.refcount = &grpc_static_metadata_refcounts[9],
+ .data.refcounted = {g_bytes + 77, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[31],
+ .data.refcounted = {g_bytes + 370, 7}}},
+ {{.refcount = &grpc_static_metadata_refcounts[5],
+ .data.refcounted = {g_bytes + 36, 2}},
+ {.refcount = &grpc_static_metadata_refcounts[32],
+ .data.refcounted = {g_bytes + 377, 8}}},
+ {{.refcount = &grpc_static_metadata_refcounts[11],
+ .data.refcounted = {g_bytes + 110, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[33],
+ .data.refcounted = {g_bytes + 385, 16}}},
+ {{.refcount = &grpc_static_metadata_refcounts[1],
+ .data.refcounted = {g_bytes + 5, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[34],
+ .data.refcounted = {g_bytes + 401, 4}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[35],
+ .data.refcounted = {g_bytes + 405, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[36],
+ .data.refcounted = {g_bytes + 408, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[4],
+ .data.refcounted = {g_bytes + 29, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[37],
+ .data.refcounted = {g_bytes + 411, 4}}},
+ {{.refcount = &grpc_static_metadata_refcounts[4],
+ .data.refcounted = {g_bytes + 29, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[38],
+ .data.refcounted = {g_bytes + 415, 5}}},
+ {{.refcount = &grpc_static_metadata_refcounts[4],
+ .data.refcounted = {g_bytes + 29, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[39],
+ .data.refcounted = {g_bytes + 420, 4}}},
+ {{.refcount = &grpc_static_metadata_refcounts[3],
+ .data.refcounted = {g_bytes + 19, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[1],
+ .data.refcounted = {g_bytes + 5, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[40],
+ .data.refcounted = {g_bytes + 424, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[1],
+ .data.refcounted = {g_bytes + 5, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[41],
+ .data.refcounted = {g_bytes + 427, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[0],
+ .data.refcounted = {g_bytes + 0, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[42],
+ .data.refcounted = {g_bytes + 430, 1}}},
+ {{.refcount = &grpc_static_metadata_refcounts[0],
+ .data.refcounted = {g_bytes + 0, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[43],
+ .data.refcounted = {g_bytes + 431, 11}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[44],
+ .data.refcounted = {g_bytes + 442, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[45],
+ .data.refcounted = {g_bytes + 445, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[46],
+ .data.refcounted = {g_bytes + 448, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[47],
+ .data.refcounted = {g_bytes + 451, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[2],
+ .data.refcounted = {g_bytes + 12, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[48],
+ .data.refcounted = {g_bytes + 454, 3}}},
+ {{.refcount = &grpc_static_metadata_refcounts[49],
+ .data.refcounted = {g_bytes + 457, 14}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[50],
+ .data.refcounted = {g_bytes + 471, 15}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[50],
+ .data.refcounted = {g_bytes + 471, 15}},
+ {.refcount = &grpc_static_metadata_refcounts[51],
+ .data.refcounted = {g_bytes + 486, 13}}},
+ {{.refcount = &grpc_static_metadata_refcounts[52],
+ .data.refcounted = {g_bytes + 499, 15}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[53],
+ .data.refcounted = {g_bytes + 514, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[54],
+ .data.refcounted = {g_bytes + 527, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[55],
+ .data.refcounted = {g_bytes + 533, 27}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[56],
+ .data.refcounted = {g_bytes + 560, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[57],
+ .data.refcounted = {g_bytes + 563, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[58],
+ .data.refcounted = {g_bytes + 568, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[59],
+ .data.refcounted = {g_bytes + 581, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[60],
+ .data.refcounted = {g_bytes + 594, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[61],
+ .data.refcounted = {g_bytes + 613, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[62],
+ .data.refcounted = {g_bytes + 629, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[63],
+ .data.refcounted = {g_bytes + 645, 14}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[64],
+ .data.refcounted = {g_bytes + 659, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[65],
+ .data.refcounted = {g_bytes + 675, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[11],
+ .data.refcounted = {g_bytes + 110, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[66],
+ .data.refcounted = {g_bytes + 688, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[67],
+ .data.refcounted = {g_bytes + 694, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[68],
+ .data.refcounted = {g_bytes + 698, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[69],
+ .data.refcounted = {g_bytes + 702, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[70],
+ .data.refcounted = {g_bytes + 708, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[71],
+ .data.refcounted = {g_bytes + 715, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[14],
+ .data.refcounted = {g_bytes + 162, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[72],
+ .data.refcounted = {g_bytes + 719, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[73],
+ .data.refcounted = {g_bytes + 727, 17}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[74],
+ .data.refcounted = {g_bytes + 744, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[75],
+ .data.refcounted = {g_bytes + 757, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[76],
+ .data.refcounted = {g_bytes + 765, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[77],
+ .data.refcounted = {g_bytes + 784, 13}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[15],
+ .data.refcounted = {g_bytes + 166, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[16],
+ .data.refcounted = {g_bytes + 174, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[78],
+ .data.refcounted = {g_bytes + 797, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[79],
+ .data.refcounted = {g_bytes + 801, 8}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[80],
+ .data.refcounted = {g_bytes + 809, 12}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[81],
+ .data.refcounted = {g_bytes + 821, 18}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[82],
+ .data.refcounted = {g_bytes + 839, 19}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[83],
+ .data.refcounted = {g_bytes + 858, 5}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[84],
+ .data.refcounted = {g_bytes + 863, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[85],
+ .data.refcounted = {g_bytes + 870, 7}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[86],
+ .data.refcounted = {g_bytes + 877, 11}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[87],
+ .data.refcounted = {g_bytes + 888, 6}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[88],
+ .data.refcounted = {g_bytes + 894, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[89],
+ .data.refcounted = {g_bytes + 904, 25}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[90],
+ .data.refcounted = {g_bytes + 929, 17}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[13],
+ .data.refcounted = {g_bytes + 152, 10}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[91],
+ .data.refcounted = {g_bytes + 946, 4}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[92],
+ .data.refcounted = {g_bytes + 950, 3}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[93],
+ .data.refcounted = {g_bytes + 953, 16}},
+ {.refcount = &grpc_static_metadata_refcounts[20],
+ .data.refcounted = {g_bytes + 227, 0}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[29],
+ .data.refcounted = {g_bytes + 358, 8}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[31],
+ .data.refcounted = {g_bytes + 370, 7}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[94],
+ .data.refcounted = {g_bytes + 969, 16}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[30],
+ .data.refcounted = {g_bytes + 366, 4}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[95],
+ .data.refcounted = {g_bytes + 985, 13}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[96],
+ .data.refcounted = {g_bytes + 998, 12}}},
+ {{.refcount = &grpc_static_metadata_refcounts[10],
+ .data.refcounted = {g_bytes + 90, 20}},
+ {.refcount = &grpc_static_metadata_refcounts[97],
+ .data.refcounted = {g_bytes + 1010, 21}}},
+};
+const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 74, 75, 76,
+ 77, 78, 79, 80};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 28ad6f2961..7649ccd5d2 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -44,375 +44,521 @@
#include "src/core/lib/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 93
-extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+#define GRPC_STATIC_MDSTR_COUNT 98
+extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
+/* ":path" */
+#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
+/* ":method" */
+#define GRPC_MDSTR_METHOD (grpc_static_slice_table[1])
+/* ":status" */
+#define GRPC_MDSTR_STATUS (grpc_static_slice_table[2])
+/* ":authority" */
+#define GRPC_MDSTR_AUTHORITY (grpc_static_slice_table[3])
+/* ":scheme" */
+#define GRPC_MDSTR_SCHEME (grpc_static_slice_table[4])
+/* "te" */
+#define GRPC_MDSTR_TE (grpc_static_slice_table[5])
+/* "grpc-message" */
+#define GRPC_MDSTR_GRPC_MESSAGE (grpc_static_slice_table[6])
+/* "grpc-status" */
+#define GRPC_MDSTR_GRPC_STATUS (grpc_static_slice_table[7])
+/* "grpc-payload-bin" */
+#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (grpc_static_slice_table[8])
+/* "grpc-encoding" */
+#define GRPC_MDSTR_GRPC_ENCODING (grpc_static_slice_table[9])
+/* "grpc-accept-encoding" */
+#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (grpc_static_slice_table[10])
+/* "content-type" */
+#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table[11])
+/* "grpc-internal-encoding-request" */
+#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (grpc_static_slice_table[12])
+/* "user-agent" */
+#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table[13])
+/* "host" */
+#define GRPC_MDSTR_HOST (grpc_static_slice_table[14])
+/* "lb-token" */
+#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[15])
+/* "lb-cost-bin" */
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[16])
+/* "grpc-timeout" */
+#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[17])
+/* "grpc-tracing-bin" */
+#define GRPC_MDSTR_GRPC_TRACING_BIN (grpc_static_slice_table[18])
+/* "grpc-stats-bin" */
+#define GRPC_MDSTR_GRPC_STATS_BIN (grpc_static_slice_table[19])
+/* "" */
+#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[20])
+/* "grpc.wait_for_ready" */
+#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[21])
+/* "grpc.timeout" */
+#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[22])
+/* "grpc.max_request_message_bytes" */
+#define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
+ (grpc_static_slice_table[23])
+/* "grpc.max_response_message_bytes" */
+#define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
+ (grpc_static_slice_table[24])
+/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
+#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
+ (grpc_static_slice_table[25])
/* "0" */
-#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
+#define GRPC_MDSTR_0 (grpc_static_slice_table[26])
/* "1" */
-#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1])
+#define GRPC_MDSTR_1 (grpc_static_slice_table[27])
/* "2" */
-#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2])
+#define GRPC_MDSTR_2 (grpc_static_slice_table[28])
+/* "identity" */
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[29])
+/* "gzip" */
+#define GRPC_MDSTR_GZIP (grpc_static_slice_table[30])
+/* "deflate" */
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[31])
+/* "trailers" */
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[32])
+/* "application/grpc" */
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[33])
+/* "POST" */
+#define GRPC_MDSTR_POST (grpc_static_slice_table[34])
/* "200" */
-#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3])
+#define GRPC_MDSTR_200 (grpc_static_slice_table[35])
+/* "404" */
+#define GRPC_MDSTR_404 (grpc_static_slice_table[36])
+/* "http" */
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[37])
+/* "https" */
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[38])
+/* "grpc" */
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[39])
+/* "GET" */
+#define GRPC_MDSTR_GET (grpc_static_slice_table[40])
+/* "PUT" */
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[41])
+/* "/" */
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[42])
+/* "/index.html" */
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[43])
/* "204" */
-#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[44])
/* "206" */
-#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[45])
/* "304" */
-#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[46])
/* "400" */
-#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7])
-/* "404" */
-#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[47])
/* "500" */
-#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9])
-/* "accept" */
-#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[48])
/* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[49])
/* "accept-encoding" */
-#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12])
+#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table[50])
+/* "gzip, deflate" */
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[51])
/* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[52])
/* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[53])
+/* "accept" */
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[54])
/* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[55])
/* "age" */
-#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[56])
/* "allow" */
-#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17])
-/* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18])
-/* ":authority" */
-#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[57])
/* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[58])
/* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[59])
/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[60])
/* "content-encoding" */
-#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23])
+#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table[61])
/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[62])
/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[63])
/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[64])
/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27])
-/* "content-type" */
-#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[65])
/* "cookie" */
-#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[66])
/* "date" */
-#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[30])
-/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[31])
-/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[32])
-/* "" */
-#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[33])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[67])
/* "etag" */
-#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[68])
/* "expect" */
-#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[69])
/* "expires" */
-#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[70])
/* "from" */
-#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[37])
-/* "GET" */
-#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[38])
-/* "grpc" */
-#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[39])
-/* "grpc-accept-encoding" */
-#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[40])
-/* "grpc-encoding" */
-#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[41])
-/* "grpc-internal-encoding-request" */
-#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[42])
-/* "grpc-message" */
-#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[43])
-/* "grpc-payload-bin" */
-#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (&grpc_static_mdstr_table[44])
-/* "grpc-stats-bin" */
-#define GRPC_MDSTR_GRPC_STATS_BIN (&grpc_static_mdstr_table[45])
-/* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
-/* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
-/* "grpc-tracing-bin" */
-#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[48])
-/* "gzip" */
-#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[49])
-/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[50])
-/* "host" */
-#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[51])
-/* "http" */
-#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[52])
-/* "https" */
-#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[53])
-/* "identity" */
-#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[54])
-/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[55])
-/* "identity,deflate,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (&grpc_static_mdstr_table[56])
-/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[57])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[71])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[58])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[72])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[59])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[73])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[60])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[74])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[61])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[75])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[62])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[76])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[63])
-/* "lb-cost-bin" */
-#define GRPC_MDSTR_LB_COST_BIN (&grpc_static_mdstr_table[64])
-/* "lb-token" */
-#define GRPC_MDSTR_LB_TOKEN (&grpc_static_mdstr_table[65])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[77])
/* "link" */
-#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[66])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[78])
/* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[67])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[79])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[68])
-/* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[69])
-/* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[70])
-/* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[80])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[81])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[73])
-/* "PUT" */
-#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[82])
/* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[83])
/* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[84])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[85])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[78])
-/* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[86])
/* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[87])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[81])
-/* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[82])
-/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[83])
-/* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[88])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[85])
-/* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[86])
-/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[87])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[89])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[88])
-/* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[89])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[90])
/* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[90])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[91])
/* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[91])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[92])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[92])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[93])
+/* "identity,deflate" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[94])
+/* "identity,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[95])
+/* "deflate,gzip" */
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[96])
+/* "identity,deflate,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
+ (grpc_static_slice_table[97])
+
+extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
+extern grpc_slice_refcount
+ grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];
+#define GRPC_IS_STATIC_METADATA_STRING(slice) \
+ ((slice).refcount != NULL && \
+ (slice).refcount->vtable == &grpc_static_metadata_vtable)
+
+#define GRPC_STATIC_METADATA_INDEX(static_slice) \
+ ((int)((static_slice).refcount - grpc_static_metadata_refcounts))
#define GRPC_STATIC_MDELEM_COUNT 81
-extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
+/* "grpc-status": "0" */
+#define GRPC_MDELEM_GRPC_STATUS_0 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-status": "1" */
+#define GRPC_MDELEM_GRPC_STATUS_1 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-status": "2" */
+#define GRPC_MDELEM_GRPC_STATUS_2 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "identity" */
+#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "gzip" */
+#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "deflate" */
+#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
+/* "te": "trailers" */
+#define GRPC_MDELEM_TE_TRAILERS \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
+/* "content-type": "application/grpc" */
+#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
+/* ":method": "POST" */
+#define GRPC_MDELEM_METHOD_POST \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "200" */
+#define GRPC_MDELEM_STATUS_200 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "404" */
+#define GRPC_MDELEM_STATUS_404 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
+/* ":scheme": "http" */
+#define GRPC_MDELEM_SCHEME_HTTP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
+/* ":scheme": "https" */
+#define GRPC_MDELEM_SCHEME_HTTPS \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
+/* ":scheme": "grpc" */
+#define GRPC_MDELEM_SCHEME_GRPC \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
+/* ":authority": "" */
+#define GRPC_MDELEM_AUTHORITY_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
+/* ":method": "GET" */
+#define GRPC_MDELEM_METHOD_GET \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
+/* ":method": "PUT" */
+#define GRPC_MDELEM_METHOD_PUT \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
+/* ":path": "/" */
+#define GRPC_MDELEM_PATH_SLASH \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
+/* ":path": "/index.html" */
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "204" */
+#define GRPC_MDELEM_STATUS_204 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "206" */
+#define GRPC_MDELEM_STATUS_206 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "304" */
+#define GRPC_MDELEM_STATUS_304 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "400" */
+#define GRPC_MDELEM_STATUS_400 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "500" */
+#define GRPC_MDELEM_STATUS_500 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-charset": "" */
-#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0])
-/* "accept": "" */
-#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1])
+#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2])
+#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
- (&grpc_static_mdelem_table[3])
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-language": "" */
-#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4])
+#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-ranges": "" */
-#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5])
+#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
+/* "accept": "" */
+#define GRPC_MDELEM_ACCEPT_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
- (&grpc_static_mdelem_table[6])
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
/* "age": "" */
-#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7])
+#define GRPC_MDELEM_AGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
/* "allow": "" */
-#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8])
-/* ":authority": "" */
-#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9])
+#define GRPC_MDELEM_ALLOW_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
/* "authorization": "" */
-#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10])
+#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
/* "cache-control": "" */
-#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11])
+#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
/* "content-disposition": "" */
-#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12])
+#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "" */
-#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13])
+#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
/* "content-language": "" */
-#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14])
+#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
/* "content-length": "" */
-#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15])
+#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
/* "content-location": "" */
-#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16])
+#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
/* "content-range": "" */
-#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17])
-/* "content-type": "application/grpc" */
-#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
- (&grpc_static_mdelem_table[18])
+#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "" */
-#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19])
+#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
/* "cookie": "" */
-#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20])
+#define GRPC_MDELEM_COOKIE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
/* "date": "" */
-#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21])
+#define GRPC_MDELEM_DATE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
/* "etag": "" */
-#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22])
+#define GRPC_MDELEM_ETAG_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
/* "expect": "" */
-#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23])
+#define GRPC_MDELEM_EXPECT_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
/* "expires": "" */
-#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24])
+#define GRPC_MDELEM_EXPIRES_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
/* "from": "" */
-#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25])
-/* "grpc-accept-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26])
-/* "grpc-accept-encoding": "deflate,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
- (&grpc_static_mdelem_table[27])
-/* "grpc-accept-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28])
-/* "grpc-accept-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
- (&grpc_static_mdelem_table[29])
-/* "grpc-accept-encoding": "identity,deflate" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
- (&grpc_static_mdelem_table[30])
-/* "grpc-accept-encoding": "identity,deflate,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (&grpc_static_mdelem_table[31])
-/* "grpc-accept-encoding": "identity,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
- (&grpc_static_mdelem_table[32])
-/* "grpc-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33])
-/* "grpc-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34])
-/* "grpc-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35])
-/* "grpc-status": "0" */
-#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36])
-/* "grpc-status": "1" */
-#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37])
-/* "grpc-status": "2" */
-#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38])
+#define GRPC_MDELEM_FROM_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
/* "host": "" */
-#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39])
+#define GRPC_MDELEM_HOST_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
/* "if-match": "" */
-#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40])
+#define GRPC_MDELEM_IF_MATCH_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
/* "if-modified-since": "" */
-#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41])
+#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
/* "if-none-match": "" */
-#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42])
+#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
/* "if-range": "" */
-#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43])
+#define GRPC_MDELEM_IF_RANGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
/* "if-unmodified-since": "" */
-#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44])
+#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
/* "last-modified": "" */
-#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
-/* "lb-cost-bin": "" */
-#define GRPC_MDELEM_LB_COST_BIN_EMPTY (&grpc_static_mdelem_table[46])
+#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
/* "lb-token": "" */
-#define GRPC_MDELEM_LB_TOKEN_EMPTY (&grpc_static_mdelem_table[47])
+#define GRPC_MDELEM_LB_TOKEN_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
+/* "lb-cost-bin": "" */
+#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
/* "link": "" */
-#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[48])
+#define GRPC_MDELEM_LINK_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
/* "location": "" */
-#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[49])
+#define GRPC_MDELEM_LOCATION_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
/* "max-forwards": "" */
-#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[50])
-/* ":method": "GET" */
-#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[51])
-/* ":method": "POST" */
-#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[52])
-/* ":method": "PUT" */
-#define GRPC_MDELEM_METHOD_PUT (&grpc_static_mdelem_table[53])
-/* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[54])
-/* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[55])
+#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authenticate": "" */
-#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[56])
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authorization": "" */
-#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[57])
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
/* "range": "" */
-#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[58])
+#define GRPC_MDELEM_RANGE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
/* "referer": "" */
-#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[59])
+#define GRPC_MDELEM_REFERER_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
/* "refresh": "" */
-#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[60])
+#define GRPC_MDELEM_REFRESH_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
/* "retry-after": "" */
-#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[61])
-/* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[62])
-/* ":scheme": "http" */
-#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[63])
-/* ":scheme": "https" */
-#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[64])
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
/* "server": "" */
-#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[65])
+#define GRPC_MDELEM_SERVER_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
/* "set-cookie": "" */
-#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[66])
-/* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[67])
-/* ":status": "204" */
-#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[68])
-/* ":status": "206" */
-#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[69])
-/* ":status": "304" */
-#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[70])
-/* ":status": "400" */
-#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[71])
-/* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[72])
-/* ":status": "500" */
-#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[73])
+#define GRPC_MDELEM_SET_COOKIE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
- (&grpc_static_mdelem_table[74])
-/* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[75])
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
/* "transfer-encoding": "" */
-#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[76])
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
/* "user-agent": "" */
-#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[77])
+#define GRPC_MDELEM_USER_AGENT_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
/* "vary": "" */
-#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[78])
+#define GRPC_MDELEM_VARY_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
/* "via": "" */
-#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[79])
+#define GRPC_MDELEM_VIA_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
/* "www-authenticate": "" */
-#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[80])
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "identity" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "deflate" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "identity,deflate" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "identity,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "deflate,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-accept-encoding": "identity,deflate,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC))
+
+grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);
+typedef enum {
+ GRPC_BATCH_PATH,
+ GRPC_BATCH_METHOD,
+ GRPC_BATCH_STATUS,
+ GRPC_BATCH_AUTHORITY,
+ GRPC_BATCH_SCHEME,
+ GRPC_BATCH_TE,
+ GRPC_BATCH_GRPC_MESSAGE,
+ GRPC_BATCH_GRPC_STATUS,
+ GRPC_BATCH_GRPC_PAYLOAD_BIN,
+ GRPC_BATCH_GRPC_ENCODING,
+ GRPC_BATCH_GRPC_ACCEPT_ENCODING,
+ GRPC_BATCH_CONTENT_TYPE,
+ GRPC_BATCH_GRPC_INTERNAL_ENCODING_REQUEST,
+ GRPC_BATCH_USER_AGENT,
+ GRPC_BATCH_HOST,
+ GRPC_BATCH_LB_TOKEN,
+ GRPC_BATCH_LB_COST_BIN,
+ GRPC_BATCH_CALLOUTS_COUNT
+} grpc_metadata_batch_callouts_index;
+
+typedef union {
+ struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];
+ struct {
+ struct grpc_linked_mdelem *path;
+ struct grpc_linked_mdelem *method;
+ struct grpc_linked_mdelem *status;
+ struct grpc_linked_mdelem *authority;
+ struct grpc_linked_mdelem *scheme;
+ struct grpc_linked_mdelem *te;
+ struct grpc_linked_mdelem *grpc_message;
+ struct grpc_linked_mdelem *grpc_status;
+ struct grpc_linked_mdelem *grpc_payload_bin;
+ struct grpc_linked_mdelem *grpc_encoding;
+ struct grpc_linked_mdelem *grpc_accept_encoding;
+ struct grpc_linked_mdelem *content_type;
+ struct grpc_linked_mdelem *grpc_internal_encoding_request;
+ struct grpc_linked_mdelem *user_agent;
+ struct grpc_linked_mdelem *host;
+ struct grpc_linked_mdelem *lb_token;
+ struct grpc_linked_mdelem *lb_cost_bin;
+ } named;
+} grpc_metadata_batch_callouts;
+
+#define GRPC_BATCH_INDEX_OF(slice) \
+ (GRPC_IS_STATIC_METADATA_STRING((slice)) \
+ ? (grpc_metadata_batch_callouts_index)GPR_CLAMP( \
+ GRPC_STATIC_METADATA_INDEX((slice)), 0, \
+ GRPC_BATCH_CALLOUTS_COUNT) \
+ : GRPC_BATCH_CALLOUTS_COUNT)
-extern const uint8_t
- grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
-extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT];
extern const uint8_t grpc_static_accept_encoding_metadata[8];
-#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
- (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]])
+#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
+ (GRPC_MAKE_MDELEM( \
+ &grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \
+ GRPC_MDELEM_STORAGE_STATIC))
#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.c b/src/core/lib/transport/status_conversion.c
index 5dce2f2d0c..af0ac89db7 100644
--- a/src/core/ext/transport/chttp2/transport/status_conversion.c
+++ b/src/core/lib/transport/status_conversion.c
@@ -31,51 +31,51 @@
*
*/
-#include "src/core/ext/transport/chttp2/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) {
case GRPC_STATUS_OK:
- return GRPC_CHTTP2_NO_ERROR;
+ return GRPC_HTTP2_NO_ERROR;
case GRPC_STATUS_CANCELLED:
- return GRPC_CHTTP2_CANCEL;
+ return GRPC_HTTP2_CANCEL;
case GRPC_STATUS_DEADLINE_EXCEEDED:
- return GRPC_CHTTP2_CANCEL;
+ return GRPC_HTTP2_CANCEL;
case GRPC_STATUS_RESOURCE_EXHAUSTED:
- return GRPC_CHTTP2_ENHANCE_YOUR_CALM;
+ return GRPC_HTTP2_ENHANCE_YOUR_CALM;
case GRPC_STATUS_PERMISSION_DENIED:
- return GRPC_CHTTP2_INADEQUATE_SECURITY;
+ return GRPC_HTTP2_INADEQUATE_SECURITY;
case GRPC_STATUS_UNAVAILABLE:
- return GRPC_CHTTP2_REFUSED_STREAM;
+ return GRPC_HTTP2_REFUSED_STREAM;
default:
- return GRPC_CHTTP2_INTERNAL_ERROR;
+ return GRPC_HTTP2_INTERNAL_ERROR;
}
}
-grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
- grpc_chttp2_error_code error, gpr_timespec deadline) {
+grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
+ gpr_timespec deadline) {
switch (error) {
- case GRPC_CHTTP2_NO_ERROR:
+ case GRPC_HTTP2_NO_ERROR:
/* should never be received */
return GRPC_STATUS_INTERNAL;
- case GRPC_CHTTP2_CANCEL:
+ case GRPC_HTTP2_CANCEL:
/* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been
* exceeded */
return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0
? GRPC_STATUS_DEADLINE_EXCEEDED
: GRPC_STATUS_CANCELLED;
- case GRPC_CHTTP2_ENHANCE_YOUR_CALM:
+ case GRPC_HTTP2_ENHANCE_YOUR_CALM:
return GRPC_STATUS_RESOURCE_EXHAUSTED;
- case GRPC_CHTTP2_INADEQUATE_SECURITY:
+ case GRPC_HTTP2_INADEQUATE_SECURITY:
return GRPC_STATUS_PERMISSION_DENIED;
- case GRPC_CHTTP2_REFUSED_STREAM:
+ case GRPC_HTTP2_REFUSED_STREAM:
return GRPC_STATUS_UNAVAILABLE;
default:
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) {
/* these HTTP2 status codes are called out explicitly in status.proto */
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) {
- return 200;
-}
+int grpc_status_to_http2_status(grpc_status_code status) { return 200; }
diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.h b/src/core/lib/transport/status_conversion.h
index 953bc9f1e1..e6a23a606b 100644
--- a/src/core/ext/transport/chttp2/transport/status_conversion.h
+++ b/src/core/lib/transport/status_conversion.h
@@ -31,20 +31,19 @@
*
*/
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H
+#ifndef GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H
+#define GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H
#include <grpc/grpc.h>
-#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/lib/transport/http2_errors.h"
/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
-grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error(
- grpc_status_code status);
-grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
- grpc_chttp2_error_code error, gpr_timespec deadline);
+grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status);
+grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
+ gpr_timespec deadline);
/* Conversion of HTTP status codes (:status) to grpc status codes */
-grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status);
-int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status);
+grpc_status_code grpc_http2_status_to_grpc_status(int status);
+int grpc_status_to_http2_status(grpc_status_code status);
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H */
+#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H */
diff --git a/src/core/lib/transport/timeout_encoding.c b/src/core/lib/transport/timeout_encoding.c
index b58ebbd0a8..0d4d7e5a7e 100644
--- a/src/core/lib/transport/timeout_encoding.c
+++ b/src/core/lib/transport/timeout_encoding.c
@@ -131,20 +131,21 @@ void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer) {
}
}
-static int is_all_whitespace(const char *p) {
- while (*p == ' ') p++;
- return *p == 0;
+static int is_all_whitespace(const char *p, const char *end) {
+ while (p != end && *p == ' ') p++;
+ return p == end;
}
-int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
+int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout) {
int32_t x = 0;
- const uint8_t *p = (const uint8_t *)buffer;
+ const uint8_t *p = GRPC_SLICE_START_PTR(text);
+ const uint8_t *end = GRPC_SLICE_END_PTR(text);
int have_digit = 0;
/* skip whitespace */
- for (; *p == ' '; p++)
+ for (; p != end && *p == ' '; p++)
;
/* decode numeric part */
- for (; *p >= '0' && *p <= '9'; p++) {
+ for (; p != end && *p >= '0' && *p <= '9'; p++) {
int32_t digit = (int32_t)(*p - (uint8_t)'0');
have_digit = 1;
/* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
@@ -158,8 +159,9 @@ int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
}
if (!have_digit) return 0;
/* skip whitespace */
- for (; *p == ' '; p++)
+ for (; p != end && *p == ' '; p++)
;
+ if (p == end) return 0;
/* decode unit specifier */
switch (*p) {
case 'n':
@@ -184,5 +186,5 @@ int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
return 0;
}
p++;
- return is_all_whitespace((const char *)p);
+ return is_all_whitespace((const char *)p, (const char *)end);
}
diff --git a/src/core/lib/transport/timeout_encoding.h b/src/core/lib/transport/timeout_encoding.h
index 92f02f6ecd..4c8025d800 100644
--- a/src/core/lib/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -34,7 +34,9 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
#define GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
+#include <grpc/slice.h>
#include <grpc/support/time.h>
+
#include "src/core/lib/support/string.h"
#define GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
@@ -42,6 +44,6 @@
/* Encode/decode timeouts to the GRPC over HTTP/2 format;
encoding may round up arbitrarily */
void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout);
#endif /* GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H */
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 055edbb39f..004e748f25 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -40,6 +40,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
@@ -69,6 +70,16 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_stream_refcount *refcount) {
#endif
if (gpr_unref(&refcount->refs)) {
+ if (exec_ctx->flags & GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP) {
+ /* Ick.
+ The thread we're running on MAY be owned (indirectly) by a call-stack.
+ If that's the case, destroying the call-stack MAY try to destroy the
+ thread, which is a tangled mess that we just don't want to ever have to
+ cope with.
+ Throw this over to the executor (on a core-owned thread) and process it
+ there. */
+ refcount->destroy.scheduler = grpc_executor_scheduler;
+ }
grpc_closure_sched(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE);
}
}
@@ -173,93 +184,7 @@ void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
GRPC_ERROR_REF(error));
grpc_closure_sched(exec_ctx, op->on_complete, error);
-}
-
-typedef struct {
- grpc_error *error;
- grpc_closure *then_call;
- grpc_closure closure;
-} close_message_data;
-
-static void free_message(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) {
- close_message_data *cmd = p;
- GRPC_ERROR_UNREF(cmd->error);
- if (cmd->then_call != NULL) {
- cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, error);
- }
- gpr_free(cmd);
-}
-
-static void add_error(grpc_transport_stream_op *op, grpc_error **which,
- grpc_error *error) {
- close_message_data *cmd;
- cmd = gpr_malloc(sizeof(*cmd));
- cmd->error = error;
- cmd->then_call = op->on_complete;
- grpc_closure_init(&cmd->closure, free_message, cmd,
- grpc_schedule_on_exec_ctx);
- op->on_complete = &cmd->closure;
- *which = error;
-}
-
-void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
- grpc_status_code status) {
- GPR_ASSERT(status != GRPC_STATUS_OK);
- if (op->cancel_error == GRPC_ERROR_NONE) {
- op->cancel_error = grpc_error_set_int(GRPC_ERROR_CANCELLED,
- GRPC_ERROR_INT_GRPC_STATUS, status);
- op->close_error = GRPC_ERROR_NONE;
- }
-}
-
-void grpc_transport_stream_op_add_cancellation_with_message(
- grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op,
- grpc_status_code status, grpc_slice *optional_message) {
- GPR_ASSERT(status != GRPC_STATUS_OK);
- if (op->cancel_error != GRPC_ERROR_NONE) {
- if (optional_message) {
- grpc_slice_unref_internal(exec_ctx, *optional_message);
- }
- return;
- }
- grpc_error *error;
- if (optional_message != NULL) {
- char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII);
- error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
- GRPC_ERROR_STR_GRPC_MESSAGE, msg);
- gpr_free(msg);
- grpc_slice_unref_internal(exec_ctx, *optional_message);
- } else {
- error = GRPC_ERROR_CREATE("Call cancelled");
- }
- error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status);
- add_error(op, &op->cancel_error, error);
-}
-
-void grpc_transport_stream_op_add_close(grpc_exec_ctx *exec_ctx,
- grpc_transport_stream_op *op,
- grpc_status_code status,
- grpc_slice *optional_message) {
- GPR_ASSERT(status != GRPC_STATUS_OK);
- if (op->cancel_error != GRPC_ERROR_NONE ||
- op->close_error != GRPC_ERROR_NONE) {
- if (optional_message) {
- grpc_slice_unref_internal(exec_ctx, *optional_message);
- }
- return;
- }
- grpc_error *error;
- if (optional_message != NULL) {
- char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII);
- error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
- GRPC_ERROR_STR_GRPC_MESSAGE, msg);
- gpr_free(msg);
- grpc_slice_unref_internal(exec_ctx, *optional_message);
- } else {
- error = GRPC_ERROR_CREATE("Call force closed");
- }
- error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status);
- add_error(op, &op->close_error, error);
+ GRPC_ERROR_UNREF(op->cancel_error);
}
typedef struct {
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index d1281830aa..9a0abe1ca4 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -150,13 +150,18 @@ typedef struct grpc_transport_stream_op {
/** Collect any stats into provided buffer, zero internal stat counters */
grpc_transport_stream_stats *collect_stats;
- /** If != GRPC_ERROR_NONE, cancel this stream */
+ /** If != GRPC_ERROR_NONE, forcefully close this stream.
+ The HTTP2 semantics should be:
+ - server side: if cancel_error has GRPC_ERROR_INT_GRPC_STATUS, and
+ trailing metadata has not been sent, send trailing metadata with status
+ and message from cancel_error (use grpc_error_get_status) followed by
+ a RST_STREAM with error=GRPC_CHTTP2_NO_ERROR to force a full close
+ - at all other times: use grpc_error_get_status to get a status code, and
+ convert to a HTTP2 error code using
+ grpc_chttp2_grpc_status_to_http2_error. Send a RST_STREAM with this
+ error. */
grpc_error *cancel_error;
- /** If != GRPC_ERROR_NONE, send grpc-status, grpc-message, and close this
- stream for both reading and writing */
- grpc_error *close_error;
-
/* Indexes correspond to grpc_context_index enum values */
grpc_call_context_element *context;
@@ -176,13 +181,8 @@ typedef struct grpc_transport_op {
grpc_connectivity_state *connectivity_state;
/** should the transport be disconnected */
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? */
- grpc_status_code goaway_status;
- grpc_slice *goaway_message;
+ grpc_error *goaway_error;
/** set the callback for accepting new streams;
this is a permanent callback, unlike the other one-shot closures.
If true, the callback is set to set_accept_stream_fn, with its
@@ -245,18 +245,6 @@ void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op,
grpc_error *error);
-void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
- grpc_status_code status);
-
-void grpc_transport_stream_op_add_cancellation_with_message(
- grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op,
- grpc_status_code status, grpc_slice *optional_message);
-
-void grpc_transport_stream_op_add_close(grpc_exec_ctx *exec_ctx,
- grpc_transport_stream_op *op,
- grpc_status_code status,
- grpc_slice *optional_message);
-
char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
char *grpc_transport_op_string(grpc_transport_op *op);
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 58d6ad508e..28360e3784 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -47,14 +47,14 @@
/* These routines are here to facilitate debugging - they produce string
representations of various transport data structures */
-static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
+static void put_metadata(gpr_strvec *b, grpc_mdelem md) {
gpr_strvec_add(b, gpr_strdup("key="));
gpr_strvec_add(
- b, grpc_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ b, grpc_dump_slice(GRPC_MDKEY(md), GPR_DUMP_HEX | GPR_DUMP_ASCII));
gpr_strvec_add(b, gpr_strdup(" value="));
gpr_strvec_add(
- b, grpc_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ b, grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII));
}
static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
@@ -121,15 +121,7 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
gpr_strvec_add(&b, gpr_strdup(" "));
const char *msg = grpc_error_string(op->cancel_error);
gpr_asprintf(&tmp, "CANCEL:%s", msg);
- grpc_error_free_string(msg);
- gpr_strvec_add(&b, tmp);
- }
- if (op->close_error != GRPC_ERROR_NONE) {
- gpr_strvec_add(&b, gpr_strdup(" "));
- const char *msg = grpc_error_string(op->close_error);
- gpr_asprintf(&tmp, "CLOSE:%s", msg);
- grpc_error_free_string(msg);
gpr_strvec_add(&b, tmp);
}
@@ -168,18 +160,14 @@ char *grpc_transport_op_string(grpc_transport_op *op) {
const char *err = grpc_error_string(op->disconnect_with_error);
gpr_asprintf(&tmp, "DISCONNECT:%s", err);
gpr_strvec_add(&b, tmp);
- grpc_error_free_string(err);
}
- if (op->send_goaway) {
+ if (op->goaway_error) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
first = false;
- char *msg = op->goaway_message == NULL
- ? "null"
- : grpc_dump_slice(*op->goaway_message,
- 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);
+ const char *msg = grpc_error_string(op->goaway_error);
+ gpr_asprintf(&tmp, "SEND_GOAWAY:%s", msg);
+
gpr_strvec_add(&b, tmp);
}