aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/census/grpc_filter.c20
-rw-r--r--src/core/channel/channel_stack.c2
-rw-r--r--src/core/channel/channel_stack.h2
-rw-r--r--src/core/channel/client_channel.c3
-rw-r--r--src/core/channel/client_uchannel.c10
-rw-r--r--src/core/channel/compress_filter.c78
-rw-r--r--src/core/channel/http_client_filter.c102
-rw-r--r--src/core/channel/http_server_filter.c104
-rw-r--r--src/core/client_config/connector.h2
-rw-r--r--src/core/client_config/default_initial_connect_string.c39
-rw-r--r--src/core/client_config/initial_connect_string.c53
-rw-r--r--src/core/client_config/initial_connect_string.h50
-rw-r--r--src/core/client_config/subchannel.c18
-rw-r--r--src/core/client_config/subchannel.h11
-rw-r--r--src/core/compression/algorithm.c50
-rw-r--r--src/core/compression/algorithm_metadata.h53
-rw-r--r--src/core/iomgr/fd_posix.c17
-rw-r--r--src/core/iomgr/fd_posix.h4
-rw-r--r--src/core/iomgr/pollset_posix.c5
-rw-r--r--src/core/iomgr/pollset_windows.c3
-rw-r--r--src/core/iomgr/tcp_client_posix.c4
-rw-r--r--src/core/iomgr/tcp_posix.c16
-rw-r--r--src/core/iomgr/tcp_posix.h6
-rw-r--r--src/core/iomgr/tcp_server.h19
-rw-r--r--src/core/iomgr/tcp_server_posix.c151
-rw-r--r--src/core/iomgr/tcp_server_windows.c121
-rw-r--r--src/core/iomgr/udp_server.c2
-rw-r--r--src/core/iomgr/workqueue_posix.c2
-rw-r--r--src/core/profiling/basic_timers.c185
-rw-r--r--src/core/profiling/timers.h2
-rw-r--r--src/core/security/client_auth_filter.c85
-rw-r--r--src/core/security/credentials.c72
-rw-r--r--src/core/security/credentials.h16
-rw-r--r--src/core/security/google_default_credentials.c3
-rw-r--r--src/core/security/security_connector.c6
-rw-r--r--src/core/security/security_connector.h2
-rw-r--r--src/core/security/server_auth_filter.c2
-rw-r--r--src/core/security/server_secure_chttp2.c15
-rw-r--r--src/core/support/avl.c288
-rw-r--r--src/core/support/slice.c15
-rw-r--r--src/core/support/thd_posix.c9
-rw-r--r--src/core/surface/byte_buffer_reader.c1
-rw-r--r--src/core/surface/call.c62
-rw-r--r--src/core/surface/channel.c115
-rw-r--r--src/core/surface/channel.h11
-rw-r--r--src/core/surface/channel_create.c39
-rw-r--r--src/core/surface/init.c2
-rw-r--r--src/core/surface/lame_client.c12
-rw-r--r--src/core/surface/secure_channel_create.c44
-rw-r--r--src/core/surface/server.c21
-rw-r--r--src/core/surface/server.h2
-rw-r--r--src/core/surface/server_chttp2.c13
-rw-r--r--src/core/transport/chttp2/hpack_encoder.c123
-rw-r--r--src/core/transport/chttp2/hpack_encoder.h32
-rw-r--r--src/core/transport/chttp2/hpack_parser.c100
-rw-r--r--src/core/transport/chttp2/hpack_parser.h3
-rw-r--r--src/core/transport/chttp2/hpack_table.c122
-rw-r--r--src/core/transport/chttp2/hpack_table.h35
-rw-r--r--src/core/transport/chttp2/internal.h13
-rw-r--r--src/core/transport/chttp2/parsing.c24
-rw-r--r--src/core/transport/chttp2/writing.c11
-rw-r--r--src/core/transport/chttp2_transport.c98
-rw-r--r--src/core/transport/chttp2_transport.h2
-rw-r--r--src/core/transport/metadata.c580
-rw-r--r--src/core/transport/metadata.h42
-rw-r--r--src/core/transport/static_metadata.c157
-rw-r--r--src/core/transport/static_metadata.h402
-rw-r--r--src/cpp/client/insecure_credentials.cc4
-rw-r--r--src/cpp/client/secure_credentials.cc25
-rw-r--r--src/cpp/client/secure_credentials.h5
-rw-r--r--src/csharp/Grpc.Core/Profiling/IProfiler.cs2
-rw-r--r--src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs3
-rw-r--r--src/csharp/Grpc.Core/Profiling/Profilers.cs13
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore3
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj60
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs46
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs76
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ClientRunners.cs153
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Control.cs2362
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj67
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Histogram.cs153
-rw-r--r--src/csharp/Grpc.IntegrationTesting/HistogramTest.cs104
-rw-r--r--src/csharp/Grpc.IntegrationTesting/IClientRunner.cs67
-rw-r--r--src/csharp/Grpc.IntegrationTesting/IServerRunner.cs72
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Payloads.cs580
-rw-r--r--src/csharp/Grpc.IntegrationTesting/QpsWorker.cs108
-rw-r--r--src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs117
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServerRunners.cs124
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Services.cs44
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs198
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Settings.StyleCop5
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Stats.cs744
-rw-r--r--src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs78
-rw-r--r--src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs96
-rw-r--r--src/csharp/Grpc.sln96
-rw-r--r--src/csharp/build_packages.bat4
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c8
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh6
-rw-r--r--src/node/ext/byte_buffer.cc1
-rw-r--r--src/node/ext/call.cc12
-rw-r--r--src/node/ext/call_credentials.cc5
-rw-r--r--src/node/ext/call_credentials.h2
-rw-r--r--src/objective-c/README.md10
-rw-r--r--src/objective-c/examples/RemoteTestClient/RemoteTest.podspec6
-rw-r--r--src/objective-c/tests/RemoteTestClient/RemoteTest.podspec8
-rwxr-xr-xsrc/objective-c/tests/run_tests.sh3
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php2
-rw-r--r--src/ruby/ext/grpc/extconf.rb4
110 files changed, 7901 insertions, 1301 deletions
diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
index daa1a7ac61..7a6ce30612 100644
--- a/src/core/census/grpc_filter.c
+++ b/src/core/census/grpc_filter.c
@@ -36,16 +36,18 @@
#include <stdio.h>
#include <string.h>
-#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/noop_filter.h"
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
#include <grpc/census.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
+#include "src/core/channel/channel_stack.h"
+#include "src/core/channel/noop_filter.h"
+#include "src/core/statistics/census_interface.h"
+#include "src/core/statistics/census_rpc_stats.h"
+#include "src/core/transport/static_metadata.h"
+
typedef struct call_data {
census_op_id op_id;
census_context *ctxt;
@@ -58,16 +60,14 @@ typedef struct call_data {
grpc_closure finish_recv;
} call_data;
-typedef struct channel_data {
- grpc_mdstr *path_str; /* pointer to meta data str with key == ":path" */
-} channel_data;
+typedef struct channel_data { gpr_uint8 unused; } channel_data;
static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
call_data *calld,
channel_data *chand) {
grpc_linked_mdelem *m;
for (m = md->list.head; m != NULL; m = m->next) {
- if (m->md->key == chand->path_str) {
+ if (m->md->key == GRPC_MDSTR_PATH) {
gpr_log(GPR_DEBUG, "%s",
(const char *)GPR_SLICE_START_PTR(m->md->value->slice));
/* Add method tag here */
@@ -161,16 +161,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(chand != NULL);
- chand->path_str = grpc_mdstr_from_string(args->metadata_context, ":path");
}
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(chand != NULL);
- if (chand->path_str != NULL) {
- GRPC_MDSTR_UNREF(chand->path_str);
- }
}
const grpc_channel_filter grpc_client_census_filter = {
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index 02e33a09ab..7f7fbf420f 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -105,7 +105,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *channel_args,
- grpc_mdctx *metadata_context,
grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
@@ -125,7 +124,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
for (i = 0; i < filter_count; i++) {
args.master = master;
args.channel_args = channel_args;
- args.metadata_context = metadata_context;
args.is_first = i == 0;
args.is_last = i == (filter_count - 1);
elems[i].filter = filters[i];
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index 5d33ab5b42..1db12ead7e 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -54,7 +54,6 @@ typedef struct grpc_call_element grpc_call_element;
typedef struct {
grpc_channel *master;
const grpc_channel_args *channel_args;
- grpc_mdctx *metadata_context;
int is_first;
int is_last;
} grpc_channel_element_args;
@@ -180,7 +179,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *args,
- grpc_mdctx *metadata_context,
grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 16d91d4277..020138bf15 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -55,8 +55,6 @@
typedef grpc_subchannel_call_holder call_data;
typedef struct client_channel_channel_data {
- /** metadata context for this channel */
- grpc_mdctx *mdctx;
/** resolver for this channel */
grpc_resolver *resolver;
/** have we started resolving this channel */
@@ -387,7 +385,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu_config);
- chand->mdctx = args->metadata_context;
chand->master = args->master;
grpc_pollset_set_init(&chand->pollset_set);
grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
diff --git a/src/core/channel/client_uchannel.c b/src/core/channel/client_uchannel.c
index ec6b02381a..456ffb7371 100644
--- a/src/core/channel/client_uchannel.c
+++ b/src/core/channel/client_uchannel.c
@@ -54,9 +54,6 @@
* load-balancing mechanisms meant for communication from within the core. */
typedef struct client_uchannel_channel_data {
- /** metadata context for this channel */
- grpc_mdctx *mdctx;
-
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
@@ -161,7 +158,6 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
- chand->mdctx = args->metadata_context;
chand->master = args->master;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_uchannel");
@@ -252,13 +248,11 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel *channel = NULL;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
- grpc_mdctx *mdctx = grpc_subchannel_get_mdctx(subchannel);
grpc_channel *master = grpc_subchannel_get_master(subchannel);
char *target = grpc_channel_get_target(master);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0;
- grpc_mdctx_ref(mdctx);
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
@@ -266,8 +260,8 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
filters[n++] = &grpc_client_uchannel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
- channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
- args, mdctx, 1);
+ channel =
+ grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
gpr_free(target);
return channel;
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index f23d8052f3..d7d1c189fe 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -39,11 +39,13 @@
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
-#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
-#include "src/core/profiling/timers.h"
+#include "src/core/channel/compress_filter.h"
+#include "src/core/compression/algorithm_metadata.h"
#include "src/core/compression/message_compress.h"
+#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
+#include "src/core/transport/static_metadata.h"
typedef struct call_data {
gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
@@ -67,20 +69,12 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
- /** Metadata key for the incoming (requested) compression algorithm */
- grpc_mdstr *mdstr_request_compression_algorithm_key;
- /** Metadata key for the outgoing (used) compression algorithm */
- grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
- /** Metadata key for the accepted encodings */
- grpc_mdstr *mdstr_compression_capabilities_key;
- /** Precomputed metadata elements for all available compression algorithms */
- grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
- /** Precomputed metadata elements for the accepted encodings */
- grpc_mdelem *mdelem_accept_encoding;
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
/** Compression options for the channel */
grpc_compression_options compression_options;
+ /** Supported compression algorithms */
+ gpr_uint32 supported_compression_algorithms;
} channel_data;
/** For each \a md element from the incoming metadata, filter out the entry for
@@ -91,7 +85,7 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
- if (md->key == channeld->mdstr_request_compression_algorithm_key) {
+ 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)) {
@@ -147,14 +141,13 @@ static void process_send_initial_metadata(
/* hint compression algorithm */
grpc_metadata_batch_add_tail(
initial_metadata, &calld->compression_algorithm_storage,
- GRPC_MDELEM_REF(
- channeld
- ->mdelem_compression_algorithms[calld->compression_algorithm]));
+ grpc_compression_encoding_mdelem(calld->compression_algorithm));
/* convey supported compression algorithms */
- grpc_metadata_batch_add_tail(
- initial_metadata, &calld->accept_encoding_storage,
- GRPC_MDELEM_REF(channeld->mdelem_accept_encoding));
+ grpc_metadata_batch_add_tail(initial_metadata,
+ &calld->accept_encoding_storage,
+ GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
+ channeld->supported_compression_algorithms));
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
@@ -266,10 +259,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
- const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1];
- size_t supported_algorithms_idx = 0;
- char *accept_encoding_str;
- size_t accept_encoding_str_len;
grpc_compression_options_init(&channeld->compression_options);
channeld->compression_options.enabled_algorithms_bitset =
@@ -284,61 +273,22 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
channeld->compression_options.default_compression_algorithm =
channeld->default_compression_algorithm;
- channeld->mdstr_request_compression_algorithm_key = grpc_mdstr_from_string(
- args->metadata_context, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY);
-
- channeld->mdstr_outgoing_compression_algorithm_key =
- grpc_mdstr_from_string(args->metadata_context, "grpc-encoding");
-
- channeld->mdstr_compression_capabilities_key =
- grpc_mdstr_from_string(args->metadata_context, "grpc-accept-encoding");
-
+ channeld->supported_compression_algorithms = 0;
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
- char *algorithm_name;
/* skip disabled algorithms */
if (grpc_compression_options_is_algorithm_enabled(
&channeld->compression_options, algo_idx) == 0) {
continue;
}
- GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
- channeld->mdelem_compression_algorithms[algo_idx] =
- grpc_mdelem_from_metadata_strings(
- args->metadata_context,
- GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
- grpc_mdstr_from_string(args->metadata_context, algorithm_name));
- if (algo_idx > 0) {
- supported_algorithms_names[supported_algorithms_idx++] = algorithm_name;
- }
+ channeld->supported_compression_algorithms |= 1u << algo_idx;
}
- /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated
- * arrays, as to avoid the heap allocs */
- accept_encoding_str =
- gpr_strjoin_sep(supported_algorithms_names, supported_algorithms_idx, ",",
- &accept_encoding_str_len);
-
- channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings(
- args->metadata_context,
- GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key),
- grpc_mdstr_from_string(args->metadata_context, accept_encoding_str));
- gpr_free(accept_encoding_str);
-
GPR_ASSERT(!args->is_last);
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
- channel_data *channeld = elem->channel_data;
- grpc_compression_algorithm algo_idx;
-
- GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key);
- GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key);
- GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key);
- for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
- GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]);
- }
- GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding);
}
const grpc_channel_filter grpc_compress_filter = {
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 3a0f68f30f..65cfb778bb 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -31,12 +31,13 @@
*/
#include "src/core/channel/http_client_filter.h"
-#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include "src/core/support/string.h"
+#include <string.h>
#include "src/core/profiling/timers.h"
+#include "src/core/support/string.h"
+#include "src/core/transport/static_metadata.h"
typedef struct call_data {
grpc_linked_mdelem method;
@@ -57,12 +58,7 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
- grpc_mdelem *te_trailers;
- grpc_mdelem *method;
- grpc_mdelem *scheme;
- grpc_mdelem *content_type;
- grpc_mdelem *status;
- /** complete user agent mdelem */
+ grpc_mdelem *static_scheme;
grpc_mdelem *user_agent;
} channel_data;
@@ -73,14 +69,12 @@ typedef struct {
static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
client_recv_filter_args *a = user_data;
- grpc_call_element *elem = a->elem;
- channel_data *channeld = elem->channel_data;
- if (md == channeld->status) {
+ if (md == GRPC_MDELEM_STATUS_200) {
return NULL;
- } else if (md->key == channeld->status->key) {
- grpc_call_element_send_cancel(a->exec_ctx, elem);
+ } else if (md->key == GRPC_MDSTR_STATUS) {
+ grpc_call_element_send_cancel(a->exec_ctx, a->elem);
return NULL;
- } else if (md->key == channeld->content_type->key) {
+ } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
return NULL;
}
return md;
@@ -98,14 +92,12 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
}
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
- grpc_call_element *elem = user_data;
- channel_data *channeld = elem->channel_data;
/* eat the things we'd like to set ourselves */
- if (md->key == channeld->method->key) return NULL;
- if (md->key == channeld->scheme->key) return NULL;
- if (md->key == channeld->te_trailers->key) return NULL;
- if (md->key == channeld->content_type->key) return NULL;
- if (md->key == channeld->user_agent->key) return NULL;
+ 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;
}
@@ -120,14 +112,14 @@ static void hc_mutate_op(grpc_call_element *elem,
/* Send : prefixed headers, which have to be before any application
layer headers. */
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
- GRPC_MDELEM_REF(channeld->method));
+ GRPC_MDELEM_METHOD_POST);
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
- GRPC_MDELEM_REF(channeld->scheme));
+ channeld->static_scheme);
grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
- GRPC_MDELEM_REF(channeld->te_trailers));
- grpc_metadata_batch_add_tail(op->send_initial_metadata,
- &calld->content_type,
- GRPC_MDELEM_REF(channeld->content_type));
+ GRPC_MDELEM_TE_TRAILERS);
+ grpc_metadata_batch_add_tail(
+ 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));
}
@@ -162,21 +154,28 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
-static const char *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};
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) {
- return args->args[i].value.string;
+ 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)) {
+ return valid_schemes[j];
+ }
+ }
}
}
}
- return "http";
+ return GRPC_MDELEM_SCHEME_HTTP;
}
-static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
- const grpc_channel_args *args) {
+static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
gpr_strvec v;
size_t i;
int is_first = 1;
@@ -218,7 +217,7 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
tmp = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v);
- result = grpc_mdstr_from_string(mdctx, tmp);
+ result = grpc_mdstr_from_string(tmp);
gpr_free(tmp);
return result;
@@ -228,43 +227,18 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- /* The first and the last filters tend to be implemented differently to
- handle the case that there's no 'next' filter to call on the up or down
- path */
+ channel_data *chand = elem->channel_data;
GPR_ASSERT(!args->is_last);
-
- /* initialize members */
- channeld->te_trailers =
- grpc_mdelem_from_strings(args->metadata_context, "te", "trailers");
- channeld->method =
- grpc_mdelem_from_strings(args->metadata_context, ":method", "POST");
- channeld->scheme = grpc_mdelem_from_strings(
- args->metadata_context, ":scheme", scheme_from_args(args->channel_args));
- channeld->content_type = grpc_mdelem_from_strings(
- args->metadata_context, "content-type", "application/grpc");
- channeld->status =
- grpc_mdelem_from_strings(args->metadata_context, ":status", "200");
- channeld->user_agent = grpc_mdelem_from_metadata_strings(
- args->metadata_context,
- grpc_mdstr_from_string(args->metadata_context, "user-agent"),
- user_agent_from_args(args->metadata_context, args->channel_args));
+ chand->static_scheme = scheme_from_args(args->channel_args);
+ chand->user_agent = grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- GRPC_MDELEM_UNREF(channeld->te_trailers);
- GRPC_MDELEM_UNREF(channeld->method);
- GRPC_MDELEM_UNREF(channeld->scheme);
- GRPC_MDELEM_UNREF(channeld->content_type);
- GRPC_MDELEM_UNREF(channeld->status);
- GRPC_MDELEM_UNREF(channeld->user_agent);
+ channel_data *chand = elem->channel_data;
+ GRPC_MDELEM_UNREF(chand->user_agent);
}
const grpc_channel_filter grpc_http_client_filter = {
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 2adfe2bb61..4f43a35ba1 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -33,10 +33,11 @@
#include "src/core/channel/http_server_filter.h"
-#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <string.h>
#include "src/core/profiling/timers.h"
+#include "src/core/transport/static_metadata.h"
typedef struct call_data {
gpr_uint8 seen_path;
@@ -57,22 +58,7 @@ typedef struct call_data {
grpc_closure hs_on_recv;
} call_data;
-typedef struct channel_data {
- grpc_mdelem *te_trailers;
- grpc_mdelem *method_post;
- grpc_mdelem *http_scheme;
- grpc_mdelem *https_scheme;
- /* TODO(klempner): Remove this once we stop using it */
- grpc_mdelem *grpc_scheme;
- grpc_mdelem *content_type;
- grpc_mdelem *status_ok;
- grpc_mdelem *status_not_found;
- grpc_mdstr *path_key;
- grpc_mdstr *authority_key;
- grpc_mdstr *host_key;
-
- grpc_mdctx *mdctx;
-} channel_data;
+typedef struct channel_data { gpr_uint8 unused; } channel_data;
typedef struct {
grpc_call_element *elem;
@@ -82,25 +68,24 @@ typedef struct {
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
server_filter_args *a = user_data;
grpc_call_element *elem = a->elem;
- channel_data *channeld = elem->channel_data;
call_data *calld = elem->call_data;
/* Check if it is one of the headers we care about. */
- if (md == channeld->te_trailers || md == channeld->method_post ||
- md == channeld->http_scheme || md == channeld->https_scheme ||
- md == channeld->grpc_scheme || md == channeld->content_type) {
+ if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
+ md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
+ md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
/* swallow it */
- if (md == channeld->method_post) {
+ if (md == GRPC_MDELEM_METHOD_POST) {
calld->seen_post = 1;
- } else if (md->key == channeld->http_scheme->key) {
+ } else if (md->key == GRPC_MDSTR_SCHEME) {
calld->seen_scheme = 1;
- } else if (md == channeld->te_trailers) {
+ } 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 == channeld->content_type->key) {
+ } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
0) {
/* Although the C implementation doesn't (currently) generate them,
@@ -112,12 +97,11 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
/* 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",
- channeld->content_type->key);
+ grpc_mdstr_as_c_string(md->value));
}
return NULL;
- } else if (md->key == channeld->te_trailers->key ||
- md->key == channeld->method_post->key ||
- md->key == channeld->http_scheme->key) {
+ } 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. */
@@ -125,22 +109,21 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
on the wire here. */
grpc_call_element_send_cancel(a->exec_ctx, elem);
return NULL;
- } else if (md->key == channeld->path_key) {
+ } else if (md->key == GRPC_MDSTR_PATH) {
if (calld->seen_path) {
gpr_log(GPR_ERROR, "Received :path twice");
return NULL;
}
calld->seen_path = 1;
return md;
- } else if (md->key == channeld->authority_key) {
+ } else if (md->key == GRPC_MDSTR_AUTHORITY) {
calld->seen_authority = 1;
return md;
- } else if (md->key == channeld->host_key) {
+ } else if (md->key == GRPC_MDSTR_HOST) {
/* translate host to :authority since :authority may be
omitted */
grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
- channeld->mdctx, GRPC_MDSTR_REF(channeld->authority_key),
- GRPC_MDSTR_REF(md->value));
+ GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
GRPC_MDELEM_UNREF(md);
calld->seen_authority = 1;
return authority;
@@ -191,15 +174,14 @@ static void hs_mutate_op(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;
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_REF(channeld->status_ok));
- grpc_metadata_batch_add_tail(op->send_initial_metadata,
- &calld->content_type,
- GRPC_MDELEM_REF(channeld->content_type));
+ 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->recv_initial_metadata) {
@@ -238,56 +220,12 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- /* The first and the last filters tend to be implemented differently to
- handle the case that there's no 'next' filter to call on the up or down
- path */
GPR_ASSERT(!args->is_last);
-
- /* initialize members */
- channeld->te_trailers =
- grpc_mdelem_from_strings(args->metadata_context, "te", "trailers");
- channeld->status_ok =
- grpc_mdelem_from_strings(args->metadata_context, ":status", "200");
- channeld->status_not_found =
- grpc_mdelem_from_strings(args->metadata_context, ":status", "404");
- channeld->method_post =
- grpc_mdelem_from_strings(args->metadata_context, ":method", "POST");
- channeld->http_scheme =
- grpc_mdelem_from_strings(args->metadata_context, ":scheme", "http");
- channeld->https_scheme =
- grpc_mdelem_from_strings(args->metadata_context, ":scheme", "https");
- channeld->grpc_scheme =
- grpc_mdelem_from_strings(args->metadata_context, ":scheme", "grpc");
- channeld->path_key = grpc_mdstr_from_string(args->metadata_context, ":path");
- channeld->authority_key =
- grpc_mdstr_from_string(args->metadata_context, ":authority");
- channeld->host_key = grpc_mdstr_from_string(args->metadata_context, "host");
- channeld->content_type = grpc_mdelem_from_strings(
- args->metadata_context, "content-type", "application/grpc");
-
- channeld->mdctx = args->metadata_context;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- GRPC_MDELEM_UNREF(channeld->te_trailers);
- GRPC_MDELEM_UNREF(channeld->status_ok);
- GRPC_MDELEM_UNREF(channeld->status_not_found);
- GRPC_MDELEM_UNREF(channeld->method_post);
- GRPC_MDELEM_UNREF(channeld->http_scheme);
- GRPC_MDELEM_UNREF(channeld->https_scheme);
- GRPC_MDELEM_UNREF(channeld->grpc_scheme);
- GRPC_MDELEM_UNREF(channeld->content_type);
- GRPC_MDSTR_UNREF(channeld->path_key);
- GRPC_MDSTR_UNREF(channeld->authority_key);
- GRPC_MDSTR_UNREF(channeld->host_key);
}
const grpc_channel_filter grpc_http_server_filter = {
diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h
index e9b8be4b53..a649f143ae 100644
--- a/src/core/client_config/connector.h
+++ b/src/core/client_config/connector.h
@@ -51,6 +51,8 @@ typedef struct {
/** address to connect to */
const struct sockaddr *addr;
size_t addr_len;
+ /** initial connect string to send */
+ gpr_slice initial_connect_string;
/** deadline for connection */
gpr_timespec deadline;
/** channel arguments (to be passed to transport) */
diff --git a/src/core/client_config/default_initial_connect_string.c b/src/core/client_config/default_initial_connect_string.c
new file mode 100644
index 0000000000..6a4e23e6f2
--- /dev/null
+++ b/src/core/client_config/default_initial_connect_string.c
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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 <grpc/support/slice.h>
+#include "src/core/iomgr/sockaddr.h"
+
+void grpc_set_default_initial_connect_string(struct sockaddr **addr,
+ size_t *addr_len,
+ gpr_slice *initial_str) {}
diff --git a/src/core/client_config/initial_connect_string.c b/src/core/client_config/initial_connect_string.c
new file mode 100644
index 0000000000..19afa1675a
--- /dev/null
+++ b/src/core/client_config/initial_connect_string.c
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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/client_config/initial_connect_string.h"
+
+#include <stddef.h>
+
+extern void grpc_set_default_initial_connect_string(struct sockaddr **addr,
+ size_t *addr_len,
+ gpr_slice *initial_str);
+
+static grpc_set_initial_connect_string_func g_set_initial_connect_string_func =
+ grpc_set_default_initial_connect_string;
+
+void grpc_test_set_initial_connect_string_function(
+ grpc_set_initial_connect_string_func func) {
+ g_set_initial_connect_string_func = func;
+}
+
+void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
+ gpr_slice *initial_str) {
+ g_set_initial_connect_string_func(addr, addr_len, initial_str);
+}
diff --git a/src/core/client_config/initial_connect_string.h b/src/core/client_config/initial_connect_string.h
new file mode 100644
index 0000000000..b6dca7134a
--- /dev/null
+++ b/src/core/client_config/initial_connect_string.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
+
+#include <grpc/support/slice.h>
+#include "src/core/iomgr/sockaddr.h"
+
+typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr,
+ size_t *addr_len,
+ gpr_slice *initial_str);
+void grpc_test_set_initial_connect_string_function(
+ grpc_set_initial_connect_string_func func);
+
+/** Set a string to be sent once connected. Optionally reset addr. */
+void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
+ gpr_slice *connect_string);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index b15a9033af..28496ac2c9 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -40,6 +40,7 @@
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
+#include "src/core/client_config/initial_connect_string.h"
#include "src/core/iomgr/timer.h"
#include "src/core/profiling/timers.h"
#include "src/core/surface/channel.h"
@@ -87,8 +88,8 @@ struct grpc_subchannel {
/** address to connect to */
struct sockaddr *addr;
size_t addr_len;
- /** metadata context */
- grpc_mdctx *mdctx;
+ /** initial string to send to peer */
+ gpr_slice initial_connect_string;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
@@ -267,7 +268,7 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
- grpc_mdctx_unref(c->mdctx);
+ gpr_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
gpr_free(c);
@@ -305,12 +306,12 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len);
c->addr_len = args->addr_len;
+ grpc_set_initial_connect_string(&c->addr, &c->addr_len,
+ &c->initial_connect_string);
c->args = grpc_channel_args_copy(args->args);
- c->mdctx = args->mdctx;
c->master = args->master;
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
c->random = random_seed();
- grpc_mdctx_ref(c->mdctx);
grpc_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
@@ -380,6 +381,7 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
args.channel_args = c->args;
+ args.initial_connect_string = c->initial_connect_string;
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected);
@@ -624,7 +626,7 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
con->refs = 0;
con->subchannel = c;
grpc_channel_stack_init(exec_ctx, filters, num_filters, c->master, c->args,
- c->mdctx, stk);
+ stk);
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
gpr_free((void *)c->connecting_result.filters);
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
@@ -871,10 +873,6 @@ static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx,
return call;
}
-grpc_mdctx *grpc_subchannel_get_mdctx(grpc_subchannel *subchannel) {
- return subchannel->mdctx;
-}
-
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel) {
return subchannel->master;
}
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
index 1fefa1888a..85ea3739e4 100644
--- a/src/core/client_config/subchannel.h
+++ b/src/core/client_config/subchannel.h
@@ -77,10 +77,10 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call (possibly asynchronously).
*
- * If the returned status is 1, the call will return immediately and \a target
- * will point to a connected \a subchannel_call instance. Note that \a notify
+ * If the returned status is 1, the call will return immediately and \a target
+ * will point to a connected \a subchannel_call instance. Note that \a notify
* will \em not be invoked in this case.
- * Otherwise, if the returned status is 0, the subchannel call will be created
+ * Otherwise, if the returned status is 0, the subchannel call will be created
* asynchronously, invoking the \a notify callback upon completion. */
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
@@ -147,8 +147,6 @@ struct grpc_subchannel_args {
/** Address to connect to */
struct sockaddr *addr;
size_t addr_len;
- /** metadata context to use */
- grpc_mdctx *mdctx;
/** master channel */
grpc_channel *master;
};
@@ -157,9 +155,6 @@ struct grpc_subchannel_args {
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args);
-/** Return the metadata context associated with the subchannel */
-grpc_mdctx *grpc_subchannel_get_mdctx(grpc_subchannel *subchannel);
-
/** Return the master channel associated with the subchannel */
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel);
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index fd95a3c891..73d91fa8ea 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -37,7 +37,9 @@
#include <grpc/compression.h>
#include <grpc/support/useful.h>
+#include "src/core/compression/algorithm_metadata.h"
#include "src/core/surface/api_trace.h"
+#include "src/core/transport/static_metadata.h"
int grpc_compression_algorithm_parse(const char *name, size_t name_length,
grpc_compression_algorithm *algorithm) {
@@ -72,17 +74,55 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
switch (algorithm) {
case GRPC_COMPRESS_NONE:
*name = "identity";
- break;
+ return 1;
case GRPC_COMPRESS_DEFLATE:
*name = "deflate";
- break;
+ return 1;
case GRPC_COMPRESS_GZIP:
*name = "gzip";
- break;
- default:
+ return 1;
+ case GRPC_COMPRESS_ALGORITHMS_COUNT:
return 0;
}
- return 1;
+ 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;
+ return GRPC_COMPRESS_ALGORITHMS_COUNT;
+}
+
+grpc_mdstr *grpc_compression_algorithm_mdstr(
+ grpc_compression_algorithm algorithm) {
+ switch (algorithm) {
+ case GRPC_COMPRESS_NONE:
+ return GRPC_MDSTR_IDENTITY;
+ case GRPC_COMPRESS_DEFLATE:
+ return GRPC_MDSTR_DEFLATE;
+ case GRPC_COMPRESS_GZIP:
+ return GRPC_MDSTR_GZIP;
+ case GRPC_COMPRESS_ALGORITHMS_COUNT:
+ return NULL;
+ }
+ return NULL;
+}
+
+grpc_mdelem *grpc_compression_encoding_mdelem(
+ grpc_compression_algorithm algorithm) {
+ switch (algorithm) {
+ case GRPC_COMPRESS_NONE:
+ return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
+ case GRPC_COMPRESS_DEFLATE:
+ return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
+ case GRPC_COMPRESS_GZIP:
+ return GRPC_MDELEM_GRPC_ENCODING_GZIP;
+ case GRPC_COMPRESS_ALGORITHMS_COUNT:
+ return NULL;
+ }
+ return NULL;
}
/* TODO(dgq): Add the ability to specify parameters to the individual
diff --git a/src/core/compression/algorithm_metadata.h b/src/core/compression/algorithm_metadata.h
new file mode 100644
index 0000000000..882633c307
--- /dev/null
+++ b/src/core/compression/algorithm_metadata.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H
+#define GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H
+
+#include <grpc/compression.h>
+#include "src/core/transport/metadata.h"
+
+/** Return compression algorithm based metadata value */
+grpc_mdstr *grpc_compression_algorithm_mdstr(
+ grpc_compression_algorithm algorithm);
+
+/** Return compression algorithm based metadata element (grpc-encoding: xxx) */
+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);
+
+#endif /* GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H */
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 7ff80e6cf8..2be0ea235f 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -207,14 +207,21 @@ static int has_watchers(grpc_fd *fd) {
}
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
- const char *reason) {
+ int *release_fd, const char *reason) {
fd->on_done_closure = on_done;
- shutdown(fd->fd, SHUT_RDWR);
+ fd->released = release_fd != NULL;
+ if (!fd->released) {
+ shutdown(fd->fd, SHUT_RDWR);
+ } else {
+ *release_fd = fd->fd;
+ }
gpr_mu_lock(&fd->mu);
REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
if (!has_watchers(fd)) {
fd->closed = 1;
- close(fd->fd);
+ if (!fd->released) {
+ close(fd->fd);
+ }
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
} else {
wake_all_watchers_locked(fd);
@@ -406,7 +413,9 @@ void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
}
if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
fd->closed = 1;
- close(fd->fd);
+ if (!fd->released) {
+ close(fd->fd);
+ }
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
}
gpr_mu_unlock(&fd->mu);
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
index dc917ebbc0..d628ef3aaf 100644
--- a/src/core/iomgr/fd_posix.h
+++ b/src/core/iomgr/fd_posix.h
@@ -62,6 +62,7 @@ struct grpc_fd {
gpr_mu mu;
int shutdown;
int closed;
+ int released;
/* The watcher list.
@@ -107,11 +108,12 @@ grpc_fd *grpc_fd_create(int fd, const char *name);
/* Releases fd to be asynchronously destroyed.
on_done is called when the underlying file descriptor is definitely close()d.
If on_done is NULL, no callback will be made.
+ If release_fd is not NULL, it's set to fd and fd will not be closed.
Requires: *fd initialized; no outstanding notify_on_read or
notify_on_write.
MUST NOT be called with a pollset lock taken */
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
- const char *reason);
+ int *release_fd, const char *reason);
/* Begin polling on an fd.
Registers that the given pollset is interested in this fd - so that if read
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 5d701fa87b..0a5577baea 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -194,6 +194,7 @@ void grpc_pollset_init(grpc_pollset *pollset) {
pollset->in_flight_cbs = 0;
pollset->shutting_down = 0;
pollset->called_shutdown = 0;
+ pollset->kicked_without_pollers = 0;
pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL;
pollset->local_wakeup_cache = NULL;
pollset->kicked_without_pollers = 0;
@@ -612,7 +613,9 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
GPR_TIMER_END("poll", 0);
if (r < 0) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ if (errno != EINTR) {
+ gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ }
if (fd) {
grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
}
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index c3f310ee27..deb661548d 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -126,7 +126,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {}
void grpc_pollset_reset(grpc_pollset *pollset) {
GPR_ASSERT(pollset->shutting_down);
- GPR_ASSERT(!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
+ GPR_ASSERT(
+ !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
pollset->shutting_down = 0;
pollset->is_iocp_worker = 0;
pollset->kicked_without_pollers = 0;
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index abd6315ca1..d9d24ee9a3 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -196,7 +196,7 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) {
finish:
if (fd != NULL) {
grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
- grpc_fd_orphan(exec_ctx, fd, NULL, "tcp_client_orphan");
+ grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan");
fd = NULL;
}
done = (--ac->refs == 0);
@@ -265,7 +265,7 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
- grpc_fd_orphan(exec_ctx, fdobj, NULL, "tcp_client_connect_error");
+ grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
goto done;
}
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 915553d509..f3be41aa57 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -90,6 +90,8 @@ typedef struct {
grpc_closure *read_cb;
grpc_closure *write_cb;
+ grpc_closure *release_fd_cb;
+ int *release_fd;
grpc_closure read_closure;
grpc_closure write_closure;
@@ -108,7 +110,8 @@ static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
}
static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
- grpc_fd_orphan(exec_ctx, tcp->em_fd, NULL, "tcp_unref_orphan");
+ grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
+ "tcp_unref_orphan");
gpr_slice_buffer_destroy(&tcp->last_read_buffer);
gpr_free(tcp->peer_string);
gpr_free(tcp);
@@ -452,6 +455,8 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
tcp->fd = em_fd->fd;
tcp->read_cb = NULL;
tcp->write_cb = NULL;
+ tcp->release_fd_cb = NULL;
+ tcp->release_fd = NULL;
tcp->incoming_buffer = NULL;
tcp->slice_size = slice_size;
tcp->iov_size = 1;
@@ -468,4 +473,13 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
return &tcp->base;
}
+void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ int *fd, grpc_closure *done) {
+ grpc_tcp *tcp = (grpc_tcp *)ep;
+ GPR_ASSERT(ep->vtable == &vtable);
+ tcp->release_fd = fd;
+ tcp->release_fd_cb = done;
+ TCP_UNREF(exec_ctx, tcp, "destroy");
+}
+
#endif
diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h
index 40b3ae2679..b554983ae1 100644
--- a/src/core/iomgr/tcp_posix.h
+++ b/src/core/iomgr/tcp_posix.h
@@ -56,4 +56,10 @@ extern int grpc_tcp_trace;
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
const char *peer_string);
+/* Destroy the tcp endpoint without closing its fd. *fd will be set and done
+ * will be called when the endpoint is destroyed.
+ * Requires: ep must be a tcp endpoint and fd must not be NULL. */
+void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ int *fd, grpc_closure *done);
+
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 882635f638..3294e13797 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -39,6 +39,9 @@
/* Forward decl of grpc_tcp_server */
typedef struct grpc_tcp_server grpc_tcp_server;
+/* Forward decl of grpc_tcp_listener */
+typedef struct grpc_tcp_listener grpc_tcp_listener;
+
/* Called for newly connected TCP connections. */
typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *ep);
@@ -51,19 +54,17 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
grpc_pollset **pollsets, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb, void *cb_arg);
-/* Add a port to the server, returning port number on success, or negative
- on failure.
+/* Add a port to the server, returning the newly created listener on success,
+ or a null pointer on failure.
The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
both IPv4 and IPv6 connections, but :: is the preferred style. This usually
creates one socket, but possibly two on systems which support IPv6,
- but not dualstack sockets.
-
- For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */
+ but not dualstack sockets. */
/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
all of the multiple socket port matching logic in one place */
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len);
+grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
+ const void *addr, size_t addr_len);
/* Returns the file descriptor of the Nth listening socket on this server,
or -1 if the index is out of bounds.
@@ -75,4 +76,8 @@ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index);
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
grpc_closure *closure);
+int grpc_tcp_listener_get_port(grpc_tcp_listener *listener);
+void grpc_tcp_listener_ref(grpc_tcp_listener *listener);
+void grpc_tcp_listener_unref(grpc_tcp_listener *listener);
+
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 99c76dcbe9..a89ee02d34 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -67,14 +67,13 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
-#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
static gpr_once s_init_max_accept_queue_size;
static int s_max_accept_queue_size;
/* one listening port */
-typedef struct {
+struct grpc_tcp_listener {
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
@@ -84,9 +83,18 @@ typedef struct {
struct sockaddr_un un;
} addr;
size_t addr_len;
+ int port;
grpc_closure read_closure;
grpc_closure destroyed_closure;
-} server_port;
+ gpr_refcount refs;
+ struct grpc_tcp_listener *next;
+ /* When we add a listener, more than one can be created, mainly because of
+ IPv6. A sibling will still be in the normal list, but will be flagged
+ as such. Any action, such as ref or unref, will affect all of the
+ siblings in the list. */
+ struct grpc_tcp_listener *sibling;
+ int is_sibling;
+};
static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
struct stat st;
@@ -112,10 +120,9 @@ struct grpc_tcp_server {
/* is this server shutting down? (boolean) */
int shutdown;
- /* all listening ports */
- server_port *ports;
- size_t nports;
- size_t port_capacity;
+ /* linked list of server ports */
+ grpc_tcp_listener *head;
+ unsigned nports;
/* shutdown callback */
grpc_closure *shutdown_complete;
@@ -134,9 +141,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
s->shutdown = 0;
s->on_accept_cb = NULL;
s->on_accept_cb_arg = NULL;
- s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
+ s->head = NULL;
s->nports = 0;
- s->port_capacity = INIT_PORT_CAP;
return s;
}
@@ -145,7 +151,12 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
gpr_mu_destroy(&s->mu);
- gpr_free(s->ports);
+ while (s->head) {
+ grpc_tcp_listener *sp = s->head;
+ s->head = sp->next;
+ grpc_tcp_listener_unref(sp);
+ }
+
gpr_free(s);
}
@@ -166,8 +177,6 @@ static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, int success) {
events will be received on them - at this point it's safe to destroy
things */
static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
- size_t i;
-
/* delete ALL the things */
gpr_mu_lock(&s->mu);
@@ -176,15 +185,15 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
return;
}
- if (s->nports) {
- for (i = 0; i < s->nports; i++) {
- server_port *sp = &s->ports[i];
+ if (s->head) {
+ grpc_tcp_listener *sp;
+ for (sp = s->head; sp; sp = sp->next) {
if (sp->addr.sockaddr.sa_family == AF_UNIX) {
unlink_if_unix_domain_socket(&sp->addr.un);
}
sp->destroyed_closure.cb = destroyed_port;
sp->destroyed_closure.cb_arg = s;
- grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure,
+ grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
"tcp_listener_shutdown");
}
gpr_mu_unlock(&s->mu);
@@ -196,7 +205,6 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_closure *closure) {
- size_t i;
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->shutdown);
@@ -206,8 +214,9 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
/* shutdown all fd's */
if (s->active_ports) {
- for (i = 0; i < s->nports; i++) {
- grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
+ grpc_tcp_listener *sp;
+ for (sp = s->head; sp; sp = sp->next) {
+ grpc_fd_shutdown(exec_ctx, sp->emfd);
}
gpr_mu_unlock(&s->mu);
} else {
@@ -298,7 +307,7 @@ error:
/* event manager callback when reads are ready */
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
- server_port *sp = arg;
+ grpc_tcp_listener *sp = arg;
grpc_fd *fdobj;
size_t i;
@@ -364,9 +373,10 @@ error:
}
}
-static int add_socket_to_server(grpc_tcp_server *s, int fd,
- const struct sockaddr *addr, size_t addr_len) {
- server_port *sp;
+static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
+ const struct sockaddr *addr,
+ size_t addr_len) {
+ grpc_tcp_listener *sp = NULL;
int port;
char *addr_str;
char *name;
@@ -376,32 +386,34 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
+ s->nports++;
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
- /* append it to the list under a lock */
- if (s->nports == s->port_capacity) {
- s->port_capacity *= 2;
- s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
- }
- sp = &s->ports[s->nports++];
+ sp = gpr_malloc(sizeof(grpc_tcp_listener));
+ sp->next = s->head;
+ s->head = sp;
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd, name);
memcpy(sp->addr.untyped, addr, addr_len);
sp->addr_len = addr_len;
+ sp->port = port;
+ sp->is_sibling = 0;
+ sp->sibling = NULL;
+ gpr_ref_init(&sp->refs, 1);
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
gpr_free(addr_str);
gpr_free(name);
}
- return port;
+ return sp;
}
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len) {
- int allocated_port1 = -1;
- int allocated_port2 = -1;
- unsigned i;
+grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
+ const void *addr, size_t addr_len) {
+ int allocated_port = -1;
+ grpc_tcp_listener *sp;
+ grpc_tcp_listener *sp2 = NULL;
int fd;
grpc_dualstack_mode dsmode;
struct sockaddr_in6 addr6_v4mapped;
@@ -420,9 +432,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
- for (i = 0; i < s->nports; i++) {
+ for (sp = s->head; sp; sp = sp->next) {
sockname_len = sizeof(sockname_temp);
- if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
+ if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp,
&sockname_len)) {
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
if (port > 0) {
@@ -436,6 +448,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
}
}
+ sp = NULL;
+
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
addr = (const struct sockaddr *)&addr6_v4mapped;
addr_len = sizeof(addr6_v4mapped);
@@ -449,14 +463,16 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
addr = (struct sockaddr *)&wild6;
addr_len = sizeof(wild6);
fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
- allocated_port1 = add_socket_to_server(s, fd, addr, addr_len);
+ sp = add_socket_to_server(s, fd, addr, addr_len);
+ allocated_port = sp->port;
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
}
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
- if (port == 0 && allocated_port1 > 0) {
- grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
+ if (port == 0 && allocated_port > 0) {
+ grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port);
+ sp2 = sp;
}
addr = (struct sockaddr *)&wild4;
addr_len = sizeof(wild4);
@@ -471,22 +487,32 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
- allocated_port2 = add_socket_to_server(s, fd, addr, addr_len);
+ sp = add_socket_to_server(s, fd, addr, addr_len);
+ sp->sibling = sp2;
+ if (sp2) sp2->is_sibling = 1;
done:
gpr_free(allocated_addr);
- return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
+ return sp;
}
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
- return (port_index < s->nports) ? s->ports[port_index].fd : -1;
+ grpc_tcp_listener *sp;
+ for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
+ ;
+ if (port_index == 0 && sp) {
+ return sp->fd;
+ } else {
+ return -1;
+ }
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_pollset **pollsets, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg) {
- size_t i, j;
+ size_t i;
+ grpc_tcp_listener *sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
@@ -495,17 +521,40 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
s->on_accept_cb_arg = on_accept_cb_arg;
s->pollsets = pollsets;
s->pollset_count = pollset_count;
- for (i = 0; i < s->nports; i++) {
- for (j = 0; j < pollset_count; j++) {
- grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
+ for (sp = s->head; sp; sp = sp->next) {
+ for (i = 0; i < pollset_count; i++) {
+ grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
}
- s->ports[i].read_closure.cb = on_read;
- s->ports[i].read_closure.cb_arg = &s->ports[i];
- grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
- &s->ports[i].read_closure);
+ sp->read_closure.cb = on_read;
+ sp->read_closure.cb_arg = sp;
+ grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
}
+int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ return sp->port;
+}
+
+void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ gpr_ref(&sp->refs);
+}
+
+void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ if (sp->is_sibling) return;
+ if (gpr_unref(&sp->refs)) {
+ grpc_tcp_listener *sibling = sp->sibling;
+ while (sibling) {
+ sp = sibling;
+ sibling = sp->sibling;
+ gpr_free(sp);
+ }
+ gpr_free(listener);
+ }
+}
+
#endif
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 3fea8b5b35..a2425cd4d2 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -35,7 +35,8 @@
#ifdef GPR_WINSOCK_SOCKET
-#define _GNU_SOURCE
+#include <io.h>
+
#include "src/core/iomgr/sockaddr_utils.h"
#include <grpc/support/alloc.h>
@@ -51,25 +52,29 @@
#include "src/core/iomgr/tcp_server.h"
#include "src/core/iomgr/tcp_windows.h"
-#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
/* one listening port */
-typedef struct server_port {
+struct grpc_tcp_listener {
/* This seemingly magic number comes from AcceptEx's documentation. each
address buffer needs to have at least 16 more bytes at their end. */
gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
/* This will hold the socket for the next accept. */
SOCKET new_socket;
- /* The listener winsocked. */
+ /* The listener winsocket. */
grpc_winsocket *socket;
+ /* The actual TCP port number. */
+ int port;
grpc_tcp_server *server;
/* The cached AcceptEx for that port. */
LPFN_ACCEPTEX AcceptEx;
int shutting_down;
/* closure for socket notification of accept being ready */
grpc_closure on_accept;
-} server_port;
+ gpr_refcount refs;
+ /* linked list */
+ struct grpc_tcp_listener *next;
+};
/* the overall server */
struct grpc_tcp_server {
@@ -82,10 +87,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
- /* all listening ports */
- server_port *ports;
- size_t nports;
- size_t port_capacity;
+ /* linked list of server ports */
+ grpc_tcp_listener *head;
/* shutdown callback */
grpc_closure *shutdown_complete;
@@ -99,9 +102,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
s->active_ports = 0;
s->on_accept_cb = NULL;
s->on_accept_cb_arg = NULL;
- s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
- s->nports = 0;
- s->port_capacity = INIT_PORT_CAP;
+ s->head = NULL;
s->shutdown_complete = NULL;
return s;
}
@@ -109,26 +110,26 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
static void dont_care_about_shutdown_completion(void *arg) {}
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
- size_t i;
-
grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
/* Now that the accepts have been aborted, we can destroy the sockets.
The IOCP won't get notified on these, so we can flag them as already
closed by the system. */
- for (i = 0; i < s->nports; i++) {
- server_port *sp = &s->ports[i];
+ while (s->head) {
+ grpc_tcp_listener *sp = s->head;
+ s->head = sp->next;
+ sp->next = NULL;
grpc_winsocket_destroy(sp->socket);
+ grpc_tcp_listener_unref(sp);
}
- gpr_free(s->ports);
gpr_free(s);
}
/* Public function. Stops and destroys a grpc_tcp_server. */
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_closure *shutdown_complete) {
- size_t i;
int immediately_done = 0;
+ grpc_tcp_listener *sp;
gpr_mu_lock(&s->mu);
s->shutdown_complete = shutdown_complete;
@@ -138,8 +139,7 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
if (s->active_ports == 0) {
immediately_done = 1;
}
- for (i = 0; i < s->nports; i++) {
- server_port *sp = &s->ports[i];
+ for (sp = s->head; sp; sp = sp->next) {
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
}
@@ -199,7 +199,7 @@ error:
}
static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
- server_port *sp) {
+ grpc_tcp_listener *sp) {
int notify = 0;
sp->shutting_down = 0;
gpr_mu_lock(&sp->server->mu);
@@ -216,7 +216,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
/* In order to do an async accept, we need to create a socket first which
will be the one assigned to the new incoming connection. */
-static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) {
+static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
SOCKET sock = INVALID_SOCKET;
char *message;
char *utf8_message;
@@ -276,7 +276,7 @@ failure:
/* Event manager callback when reads are ready. */
static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
- server_port *sp = arg;
+ grpc_tcp_listener *sp = arg;
SOCKET sock = sp->new_socket;
grpc_winsocket_callback_info *info = &sp->socket->read_info;
grpc_endpoint *ep = NULL;
@@ -351,16 +351,17 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
start_accept(exec_ctx, sp);
}
-static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
- const struct sockaddr *addr, size_t addr_len) {
- server_port *sp;
+static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
+ const struct sockaddr *addr,
+ size_t addr_len) {
+ grpc_tcp_listener *sp = NULL;
int port;
int status;
GUID guid = WSAID_ACCEPTEX;
DWORD ioctl_num_bytes;
LPFN_ACCEPTEX AcceptEx;
- if (sock == INVALID_SOCKET) return -1;
+ if (sock == INVALID_SOCKET) return NULL;
/* We need to grab the AcceptEx pointer for that port, as it may be
interface-dependent. We'll cache it to avoid doing that again. */
@@ -373,37 +374,34 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
gpr_free(utf8_message);
closesocket(sock);
- return -1;
+ return NULL;
}
port = prepare_socket(sock, addr, addr_len);
if (port >= 0) {
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
- /* append it to the list under a lock */
- if (s->nports == s->port_capacity) {
- /* too many ports, and we need to store their address in a closure */
- /* TODO(ctiller): make server_port a linked list */
- abort();
- }
- sp = &s->ports[s->nports++];
+ sp = gpr_malloc(sizeof(grpc_tcp_listener));
+ sp->next = s->head;
+ s->head = sp;
sp->server = s;
sp->socket = grpc_winsocket_create(sock, "listener");
sp->shutting_down = 0;
sp->AcceptEx = AcceptEx;
sp->new_socket = INVALID_SOCKET;
+ sp->port = port;
+ gpr_ref_init(&sp->refs, 1);
grpc_closure_init(&sp->on_accept, on_accept, sp);
GPR_ASSERT(sp->socket);
gpr_mu_unlock(&s->mu);
}
- return port;
+ return sp;
}
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len) {
- int allocated_port = -1;
- unsigned i;
+grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
+ const void *addr, size_t addr_len) {
+ grpc_tcp_listener *sp;
SOCKET sock;
struct sockaddr_in6 addr6_v4mapped;
struct sockaddr_in6 wildcard;
@@ -415,9 +413,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
- for (i = 0; i < s->nports; i++) {
+ for (sp = s->head; sp; sp = sp->next) {
sockname_len = sizeof(sockname_temp);
- if (0 == getsockname(s->ports[i].socket->socket,
+ if (0 == getsockname(sp->socket->socket,
(struct sockaddr *)&sockname_temp, &sockname_len)) {
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
if (port > 0) {
@@ -452,33 +450,56 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
gpr_free(utf8_message);
}
- allocated_port = add_socket_to_server(s, sock, addr, addr_len);
+ sp = add_socket_to_server(s, sock, addr, addr_len);
gpr_free(allocated_addr);
- return allocated_port;
+ return sp;
}
-SOCKET
-grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
- return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
+int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
+ grpc_tcp_listener *sp;
+ for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
+ ;
+ if (port_index == 0 && sp) {
+ return _open_osfhandle(sp->socket->socket, 0);
+ } else {
+ return -1;
+ }
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_pollset **pollset, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg) {
- size_t i;
+ grpc_tcp_listener *sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0);
s->on_accept_cb = on_accept_cb;
s->on_accept_cb_arg = on_accept_cb_arg;
- for (i = 0; i < s->nports; i++) {
- start_accept(exec_ctx, s->ports + i);
+ for (sp = s->head; sp; sp = sp->next) {
+ start_accept(exec_ctx, sp);
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
}
+int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ return sp->port;
+}
+
+void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ gpr_ref(&sp->refs);
+}
+
+void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
+ grpc_tcp_listener *sp = listener;
+ if (gpr_unref(&sp->refs)) {
+ gpr_free(listener);
+ }
+}
+
#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
index 9903e970e6..782fbd9f46 100644
--- a/src/core/iomgr/udp_server.c
+++ b/src/core/iomgr/udp_server.c
@@ -179,7 +179,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
}
sp->destroyed_closure.cb = destroyed_port;
sp->destroyed_closure.cb_arg = s;
- grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure,
+ grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
"udp_listener_shutdown");
}
gpr_mu_unlock(&s->mu);
diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c
index c087b887b8..2e30178131 100644
--- a/src/core/iomgr/workqueue_posix.c
+++ b/src/core/iomgr/workqueue_posix.c
@@ -115,7 +115,7 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, int success) {
/* HACK: let wakeup_fd code know that we stole the fd */
workqueue->wakeup_fd.read_fd = 0;
grpc_wakeup_fd_destroy(&workqueue->wakeup_fd);
- grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, "destroy");
+ grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy");
gpr_free(workqueue);
} else {
gpr_mu_lock(&workqueue->mu);
diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c
index 527a160101..f0fce7858d 100644
--- a/src/core/profiling/basic_timers.c
+++ b/src/core/profiling/basic_timers.c
@@ -53,50 +53,186 @@ typedef struct gpr_timer_entry {
short line;
char type;
gpr_uint8 important;
+ int thd;
} gpr_timer_entry;
-#define MAX_COUNT (5 * 1024 * 1024 / sizeof(gpr_timer_entry))
+#define MAX_COUNT 1000000
-static __thread gpr_timer_entry g_log[MAX_COUNT];
-static __thread int g_count;
+typedef struct gpr_timer_log {
+ size_t num_entries;
+ struct gpr_timer_log *next;
+ struct gpr_timer_log *prev;
+ gpr_timer_entry log[MAX_COUNT];
+} gpr_timer_log;
+
+typedef struct gpr_timer_log_list {
+ gpr_timer_log *head;
+ /* valid iff head!=NULL */
+ gpr_timer_log *tail;
+} gpr_timer_log_list;
+
+static __thread gpr_timer_log *g_thread_log;
static gpr_once g_once_init = GPR_ONCE_INIT;
static FILE *output_file;
+static const char *output_filename = "latency_trace.txt";
+static pthread_mutex_t g_mu;
+static pthread_cond_t g_cv;
+static gpr_timer_log_list g_in_progress_logs;
+static gpr_timer_log_list g_done_logs;
+static int g_shutdown;
+static gpr_thd_id g_writing_thread;
+static __thread int g_thread_id;
+static int g_next_thread_id;
-static void close_output() { fclose(output_file); }
+static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
+ if (list->head == NULL) {
+ list->head = list->tail = log;
+ log->next = log->prev = NULL;
+ return 1;
+ } else {
+ log->prev = list->tail;
+ log->next = NULL;
+ list->tail->next = log;
+ list->tail = log;
+ return 0;
+ }
+}
-static void init_output() {
- output_file = fopen("latency_trace.txt", "w");
- GPR_ASSERT(output_file);
- atexit(close_output);
+static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) {
+ gpr_timer_log *out = list->head;
+ if (out != NULL) {
+ list->head = out->next;
+ if (list->head != NULL) {
+ list->head->prev = NULL;
+ } else {
+ list->tail = NULL;
+ }
+ }
+ return out;
}
-static void log_report() {
- int i;
- gpr_once_init(&g_once_init, init_output);
- for (i = 0; i < g_count; i++) {
- gpr_timer_entry *entry = &(g_log[i]);
+static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) {
+ if (log->prev == NULL) {
+ list->head = log->next;
+ if (list->head != NULL) {
+ list->head->prev = NULL;
+ }
+ } else {
+ log->prev->next = log->next;
+ }
+ if (log->next == NULL) {
+ list->tail = log->prev;
+ if (list->tail != NULL) {
+ list->tail->next = NULL;
+ }
+ } else {
+ log->next->prev = log->prev;
+ }
+}
+
+static void write_log(gpr_timer_log *log) {
+ size_t i;
+ if (output_file == NULL) {
+ output_file = fopen(output_filename, "w");
+ }
+ for (i = 0; i < log->num_entries; i++) {
+ gpr_timer_entry *entry = &(log->log[i]);
+ if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) {
+ entry->tm = gpr_time_0(entry->tm.clock_type);
+ }
fprintf(output_file,
- "{\"t\": %ld.%09d, \"thd\": \"%p\", \"type\": \"%c\", \"tag\": "
+ "{\"t\": %ld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
"\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
- entry->tm.tv_sec, entry->tm.tv_nsec,
- (void *)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tagstr,
- entry->file, entry->line, entry->important);
+ entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd, entry->type,
+ entry->tagstr, entry->file, entry->line, entry->important);
+ }
+}
+
+static void writing_thread(void *unused) {
+ gpr_timer_log *log;
+ pthread_mutex_lock(&g_mu);
+ for (;;) {
+ while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) {
+ pthread_cond_wait(&g_cv, &g_mu);
+ }
+ if (log != NULL) {
+ pthread_mutex_unlock(&g_mu);
+ write_log(log);
+ free(log);
+ pthread_mutex_lock(&g_mu);
+ }
+ if (g_shutdown) {
+ pthread_mutex_unlock(&g_mu);
+ return;
+ }
}
+}
- /* Now clear out the log */
- g_count = 0;
+static void flush_logs(gpr_timer_log_list *list) {
+ gpr_timer_log *log;
+ while ((log = timer_log_pop_front(list)) != NULL) {
+ write_log(log);
+ free(log);
+ }
+}
+
+static void finish_writing() {
+ pthread_mutex_lock(&g_mu);
+ g_shutdown = 1;
+ pthread_cond_signal(&g_cv);
+ pthread_mutex_unlock(&g_mu);
+ gpr_thd_join(g_writing_thread);
+
+ gpr_log(GPR_INFO, "flushing logs");
+
+ pthread_mutex_lock(&g_mu);
+ flush_logs(&g_done_logs);
+ flush_logs(&g_in_progress_logs);
+ pthread_mutex_unlock(&g_mu);
+
+ if (output_file) {
+ fclose(output_file);
+ }
+}
+
+void gpr_timers_set_log_filename(const char *filename) {
+ output_filename = filename;
+}
+
+static void init_output() {
+ gpr_thd_options options = gpr_thd_options_default();
+ gpr_thd_options_set_joinable(&options);
+ gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options);
+ atexit(finish_writing);
+}
+
+static void rotate_log() {
+ gpr_timer_log *new = malloc(sizeof(*new));
+ gpr_once_init(&g_once_init, init_output);
+ new->num_entries = 0;
+ pthread_mutex_lock(&g_mu);
+ if (g_thread_log != NULL) {
+ timer_log_remove(&g_in_progress_logs, g_thread_log);
+ if (timer_log_push_back(&g_done_logs, g_thread_log)) {
+ pthread_cond_signal(&g_cv);
+ }
+ } else {
+ g_thread_id = g_next_thread_id++;
+ }
+ timer_log_push_back(&g_in_progress_logs, new);
+ pthread_mutex_unlock(&g_mu);
+ g_thread_log = new;
}
static void gpr_timers_log_add(const char *tagstr, marker_type type,
int important, const char *file, int line) {
gpr_timer_entry *entry;
- /* TODO (vpai) : Improve concurrency */
- if (g_count == MAX_COUNT) {
- log_report();
+ if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
+ rotate_log();
}
- entry = &g_log[g_count++];
+ entry = &g_thread_log->log[g_thread_log->num_entries++];
entry->tm = gpr_now(GPR_CLOCK_PRECISE);
entry->tagstr = tagstr;
@@ -104,6 +240,7 @@ static void gpr_timers_log_add(const char *tagstr, marker_type type,
entry->file = file;
entry->line = (short)line;
entry->important = important != 0;
+ entry->thd = g_thread_id;
}
/* Latency profiler API implementation. */
@@ -131,4 +268,6 @@ void gpr_timers_global_destroy(void) {}
void gpr_timers_global_init(void) {}
void gpr_timers_global_destroy(void) {}
+
+void gpr_timers_set_log_filename(const char *filename) {}
#endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
index 0d112e7248..6a188dc566 100644
--- a/src/core/profiling/timers.h
+++ b/src/core/profiling/timers.h
@@ -48,6 +48,8 @@ void gpr_timer_begin(const char *tagstr, int important, const char *file,
void gpr_timer_end(const char *tagstr, int important, const char *file,
int line);
+void gpr_timers_set_log_filename(const char *filename);
+
#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
/* No profiling. No-op all the things. */
#define GPR_TIMER_MARK(tag, important) \
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index be2522a7a0..b1fd733c91 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -39,12 +39,13 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include "src/core/support/string.h"
#include "src/core/channel/channel_stack.h"
-#include "src/core/security/security_context.h"
-#include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h"
+#include "src/core/security/security_connector.h"
+#include "src/core/security/security_context.h"
+#include "src/core/support/string.h"
#include "src/core/surface/call.h"
+#include "src/core/transport/static_metadata.h"
#define MAX_CREDENTIALS_METADATA_COUNT 4
@@ -61,24 +62,28 @@ typedef struct {
grpc_transport_stream_op op;
gpr_uint8 security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
- char *service_url;
+ grpc_auth_metadata_context auth_md_context;
} call_data;
/* We can have a per-channel credentials. */
typedef struct {
grpc_channel_security_connector *security_connector;
- grpc_mdctx *md_ctx;
- grpc_mdstr *authority_string;
- grpc_mdstr *path_string;
- grpc_mdstr *error_msg_key;
- grpc_mdstr *status_key;
} channel_data;
-static void reset_service_url(call_data *calld) {
- if (calld->service_url != NULL) {
- gpr_free(calld->service_url);
- calld->service_url = NULL;
+static void reset_auth_metadata_context(
+ grpc_auth_metadata_context *auth_md_context) {
+ if (auth_md_context->service_url != NULL) {
+ gpr_free((char *)auth_md_context->service_url);
+ auth_md_context->service_url = NULL;
}
+ if (auth_md_context->method_name != NULL) {
+ gpr_free((char *)auth_md_context->method_name);
+ auth_md_context->method_name = NULL;
+ }
+ GRPC_AUTH_CONTEXT_UNREF(
+ (grpc_auth_context *)auth_md_context->channel_auth_context,
+ "grpc_auth_metadata_context");
+ auth_md_context->channel_auth_context = NULL;
}
static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
@@ -95,11 +100,10 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_credentials_status status) {
grpc_call_element *elem = (grpc_call_element *)user_data;
call_data *calld = elem->call_data;
- channel_data *chand = elem->channel_data;
grpc_transport_stream_op *op = &calld->op;
grpc_metadata_batch *mdb;
size_t i;
- reset_service_url(calld);
+ reset_auth_metadata_context(&calld->auth_md_context);
if (status != GRPC_CREDENTIALS_OK) {
bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
"Credentials failed to get metadata.");
@@ -111,15 +115,19 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
for (i = 0; i < num_md; i++) {
grpc_metadata_batch_add_tail(
mdb, &calld->md_links[i],
- grpc_mdelem_from_slices(chand->md_ctx, gpr_slice_ref(md_elems[i].key),
+ grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key),
gpr_slice_ref(md_elems[i].value)));
}
grpc_call_next_op(exec_ctx, elem, op);
}
-void build_service_url(const char *url_scheme, call_data *calld) {
+void build_auth_metadata_context(grpc_security_connector *sc,
+ call_data *calld) {
char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
char *last_slash = strrchr(service, '/');
+ char *method_name = NULL;
+ char *service_url = NULL;
+ reset_auth_metadata_context(&calld->auth_md_context);
if (last_slash == NULL) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service[0] = '\0';
@@ -128,11 +136,16 @@ void build_service_url(const char *url_scheme, call_data *calld) {
service[1] = '\0';
} else {
*last_slash = '\0';
+ method_name = gpr_strdup(last_slash + 1);
}
- if (url_scheme == NULL) url_scheme = "";
- reset_service_url(calld);
- gpr_asprintf(&calld->service_url, "%s://%s%s", url_scheme,
+ if (method_name == NULL) method_name = gpr_strdup("");
+ gpr_asprintf(&service_url, "%s://%s%s",
+ sc->url_scheme == NULL ? "" : sc->url_scheme,
grpc_mdstr_as_c_string(calld->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(sc->auth_context, "grpc_auth_metadata_context");
gpr_free(service);
}
@@ -166,12 +179,12 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
call_creds_has_md ? ctx->creds : channel_call_creds);
}
- build_service_url(chand->security_connector->base.url_scheme, calld);
+ build_auth_metadata_context(&chand->security_connector->base, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */
GPR_ASSERT(calld->pollset);
- grpc_call_credentials_get_request_metadata(exec_ctx, calld->creds,
- calld->pollset, calld->service_url,
- on_credentials_metadata, elem);
+ grpc_call_credentials_get_request_metadata(
+ exec_ctx, calld->creds, calld->pollset, calld->auth_md_context,
+ on_credentials_metadata, elem);
}
static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -225,10 +238,10 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_mdelem *md = l->md;
/* Pointer comparison is OK for md_elems created from the same context.
*/
- if (md->key == chand->authority_string) {
+ if (md->key == GRPC_MDSTR_AUTHORITY) {
if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
calld->host = GRPC_MDSTR_REF(md->value);
- } else if (md->key == chand->path_string) {
+ } else if (md->key == GRPC_MDSTR_PATH) {
if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
calld->method = GRPC_MDSTR_REF(md->value);
}
@@ -285,7 +298,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
if (calld->method != NULL) {
GRPC_MDSTR_UNREF(calld->method);
}
- reset_service_url(calld);
+ reset_auth_metadata_context(&calld->auth_md_context);
}
/* Constructor for channel_data */
@@ -308,11 +321,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
chand->security_connector =
(grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
sc, "client_auth_filter");
- chand->md_ctx = args->metadata_context;
- chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
- chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
- chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
- chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
}
/* Destructor for channel data */
@@ -321,19 +329,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
grpc_channel_security_connector *ctx = chand->security_connector;
- if (ctx != NULL)
+ if (ctx != NULL) {
GRPC_SECURITY_CONNECTOR_UNREF(&ctx->base, "client_auth_filter");
- if (chand->authority_string != NULL) {
- GRPC_MDSTR_UNREF(chand->authority_string);
- }
- if (chand->error_msg_key != NULL) {
- GRPC_MDSTR_UNREF(chand->error_msg_key);
- }
- if (chand->status_key != NULL) {
- GRPC_MDSTR_UNREF(chand->status_key);
- }
- if (chand->path_string != NULL) {
- GRPC_MDSTR_UNREF(chand->path_string);
}
}
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 3db531cd35..543c75044b 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -33,16 +33,16 @@
#include "src/core/security/credentials.h"
-#include <string.h>
#include <stdio.h>
+#include <string.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/http_client_filter.h"
-#include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h"
-#include "src/core/surface/api_trace.h"
+#include "src/core/json/json.h"
#include "src/core/support/string.h"
+#include "src/core/surface/api_trace.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@@ -117,15 +117,16 @@ void grpc_call_credentials_release(grpc_call_credentials *creds) {
}
void grpc_call_credentials_get_request_metadata(
- grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
- const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+ grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_credentials_metadata_cb cb, void *user_data) {
if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
if (cb != NULL) {
cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
}
return;
}
- creds->vtable->get_request_metadata(exec_ctx, creds, pollset, service_url, cb,
+ creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb,
user_data);
}
@@ -423,9 +424,12 @@ static void jwt_destruct(grpc_call_credentials *creds) {
gpr_mu_destroy(&c->cache_mu);
}
-static void jwt_get_request_metadata(
- grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
- const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_call_credentials *creds,
+ grpc_pollset *pollset,
+ grpc_auth_metadata_context context,
+ grpc_credentials_metadata_cb cb,
+ void *user_data) {
grpc_service_account_jwt_access_credentials *c =
(grpc_service_account_jwt_access_credentials *)creds;
gpr_timespec refresh_threshold = gpr_time_from_seconds(
@@ -436,7 +440,7 @@ static void jwt_get_request_metadata(
{
gpr_mu_lock(&c->cache_mu);
if (c->cached.service_url != NULL &&
- strcmp(c->cached.service_url, service_url) == 0 &&
+ strcmp(c->cached.service_url, context.service_url) == 0 &&
c->cached.jwt_md != NULL &&
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
gpr_now(GPR_CLOCK_REALTIME)),
@@ -451,14 +455,15 @@ static void jwt_get_request_metadata(
/* Generate a new jwt. */
gpr_mu_lock(&c->cache_mu);
jwt_reset_cache(c);
- jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
+ jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
+ c->jwt_lifetime, NULL);
if (jwt != NULL) {
char *md_value;
gpr_asprintf(&md_value, "Bearer %s", jwt);
gpr_free(jwt);
c->cached.jwt_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
- c->cached.service_url = gpr_strdup(service_url);
+ c->cached.service_url = gpr_strdup(context.service_url);
c->cached.jwt_md = grpc_credentials_md_store_create(1);
grpc_credentials_md_store_add_cstrings(
c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
@@ -643,7 +648,7 @@ static void on_oauth2_token_fetcher_http_response(
static void oauth2_token_fetcher_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, const char *service_url,
+ grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
@@ -799,8 +804,9 @@ static void on_simulated_token_fetch_done(void *user_data) {
}
static void md_only_test_get_request_metadata(
- grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
- const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+ grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_credentials_metadata_cb cb, void *user_data) {
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) {
@@ -838,8 +844,9 @@ static void access_token_destruct(grpc_call_credentials *creds) {
}
static void access_token_get_request_metadata(
- grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
- const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+ grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_credentials_metadata_cb cb, void *user_data) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
}
@@ -920,7 +927,7 @@ typedef struct {
grpc_composite_call_credentials *composite_creds;
size_t creds_index;
grpc_credentials_md_store *md_elems;
- char *service_url;
+ grpc_auth_metadata_context auth_md_context;
void *user_data;
grpc_pollset *pollset;
grpc_credentials_metadata_cb cb;
@@ -938,7 +945,6 @@ static void composite_call_destruct(grpc_call_credentials *creds) {
static void composite_call_md_context_destroy(
grpc_composite_call_credentials_metadata_context *ctx) {
grpc_credentials_md_store_unref(ctx->md_elems);
- if (ctx->service_url != NULL) gpr_free(ctx->service_url);
gpr_free(ctx);
}
@@ -966,9 +972,9 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
grpc_call_credentials *inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
- grpc_call_credentials_get_request_metadata(exec_ctx, inner_creds,
- ctx->pollset, ctx->service_url,
- composite_call_metadata_cb, ctx);
+ grpc_call_credentials_get_request_metadata(
+ exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
+ composite_call_metadata_cb, ctx);
return;
}
@@ -979,22 +985,23 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
}
static void composite_call_get_request_metadata(
- grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
- const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+ grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
+ grpc_credentials_metadata_cb cb, void *user_data) {
grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
grpc_composite_call_credentials_metadata_context *ctx;
ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
- ctx->service_url = gpr_strdup(service_url);
+ ctx->auth_md_context = auth_md_context;
ctx->user_data = user_data;
ctx->cb = cb;
ctx->composite_creds = c;
ctx->pollset = pollset;
ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
grpc_call_credentials_get_request_metadata(
- exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, service_url,
- composite_call_metadata_cb, ctx);
+ exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
+ auth_md_context, composite_call_metadata_cb, ctx);
}
static grpc_call_credentials_vtable composite_call_credentials_vtable = {
@@ -1088,7 +1095,7 @@ static void iam_destruct(grpc_call_credentials *creds) {
static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
- const char *service_url,
+ grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
@@ -1097,7 +1104,7 @@ static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
}
static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
- iam_get_request_metadata};
+ iam_get_request_metadata};
grpc_call_credentials *grpc_google_iam_credentials_create(
const char *token, const char *authority_selector, void *reserved) {
@@ -1177,7 +1184,7 @@ static void plugin_md_request_metadata_ready(void *request,
static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
- const char *service_url,
+ grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
@@ -1186,7 +1193,7 @@ static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
memset(request, 0, sizeof(*request));
request->user_data = user_data;
request->cb = cb;
- c->plugin.get_metadata(c->plugin.state, service_url,
+ c->plugin.get_metadata(c->plugin.state, context,
plugin_md_request_metadata_ready, request);
} else {
cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
@@ -1203,7 +1210,7 @@ grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
(reserved));
GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(*c));
- c->base.type = GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN;
+ c->base.type = plugin.type;
c->base.vtable = &plugin_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->plugin = plugin;
@@ -1265,4 +1272,3 @@ grpc_channel_credentials *grpc_composite_channel_credentials_create(
c->call_creds = grpc_call_credentials_ref(call_creds);
return &c->base;
}
-
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 559574d514..6d45895e77 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -59,7 +59,6 @@ typedef enum {
"FakeTransportSecurity"
#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
-#define GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt"
#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam"
#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite"
@@ -162,7 +161,7 @@ typedef struct {
void (*destruct)(grpc_call_credentials *c);
void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *c, grpc_pollset *pollset,
- const char *service_url,
+ grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data);
} grpc_call_credentials_vtable;
@@ -175,19 +174,18 @@ struct grpc_call_credentials {
grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
void grpc_call_credentials_unref(grpc_call_credentials *creds);
-void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx,
- grpc_call_credentials *creds,
- grpc_pollset *pollset,
- const char *service_url,
- grpc_credentials_metadata_cb cb,
- void *user_data);
+void grpc_call_credentials_get_request_metadata(
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+ grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_credentials_metadata_cb cb, void *user_data);
typedef struct {
grpc_call_credentials **creds_array;
size_t num_creds;
} grpc_call_credentials_array;
-const grpc_call_credentials_array *grpc_composite_call_credentials_get_credentials(
+const grpc_call_credentials_array *
+grpc_composite_call_credentials_get_credentials(
grpc_call_credentials *composite_creds);
/* Returns creds if creds is of the specified type or the inner creds of the
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index e5a810f23c..6a54fe4e47 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -214,7 +214,8 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
end:
if (result == NULL) {
if (call_creds != NULL) {
- /* Blend with default ssl credentials and add a global reference so that it
+ /* Blend with default ssl credentials and add a global reference so that
+ it
can be cached and re-served. */
grpc_channel_credentials *ssl_creds =
grpc_ssl_credentials_create(NULL, NULL, NULL);
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 96240170b8..8c6ab0b8a4 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -591,9 +591,9 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
}
grpc_security_status grpc_ssl_channel_security_connector_create(
- grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config,
- const char *target_name, const char *overridden_target_name,
- grpc_channel_security_connector **sc) {
+ grpc_call_credentials *request_metadata_creds,
+ const grpc_ssl_config *config, const char *target_name,
+ const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index f2372e0856..7edb05a662 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -91,8 +91,10 @@ struct grpc_security_connector {
const char *url_scheme;
grpc_auth_context *auth_context; /* Populated after the peer is checked. */
/* Used on server side only. */
+ /* TODO(yangg) maybe create a grpc_server_security_connector with these */
gpr_mu mu;
grpc_security_connector_handshake_list *handshaking_handshakes;
+ const grpc_channel_args *channel_args;
};
/* Refcounting. */
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index fee962b576..5cfee6d139 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -58,7 +58,6 @@ typedef struct call_data {
typedef struct channel_data {
grpc_auth_context *auth_context;
grpc_server_credentials *creds;
- grpc_mdctx *mdctx;
} channel_data;
static grpc_metadata_array metadata_batch_to_md_array(
@@ -247,7 +246,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
chand->auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
chand->creds = grpc_server_credentials_ref(creds);
- chand->mdctx = args->metadata_context;
}
/* Destructor for channel data */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index e0a6c641ed..6bda8a360c 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -81,7 +81,7 @@ static void state_unref(grpc_server_secure_state *state) {
}
static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
- grpc_transport *transport, grpc_mdctx *mdctx) {
+ grpc_transport *transport) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_server_auth_filter, &grpc_http_server_filter};
grpc_server_secure_state *state = statep;
@@ -93,7 +93,7 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_server_get_channel_args(state->server), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
- GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy);
+ GPR_ARRAY_SIZE(extra_filters), args_copy);
grpc_channel_args_destroy(args_copy);
}
@@ -102,16 +102,14 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_endpoint *secure_endpoint) {
grpc_server_secure_state *state = statep;
grpc_transport *transport;
- grpc_mdctx *mdctx;
if (status == GRPC_SECURITY_OK) {
if (secure_endpoint) {
gpr_mu_lock(&state->mu);
if (!state->is_shutdown) {
- mdctx = grpc_mdctx_create();
transport = grpc_create_chttp2_transport(
exec_ctx, grpc_server_get_channel_args(state->server),
- secure_endpoint, mdctx, 0);
- setup_transport(exec_ctx, state, transport, mdctx);
+ secure_endpoint, 0);
+ setup_transport(exec_ctx, state, transport);
grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
} else {
/* We need to consume this here, because the server may already have
@@ -192,6 +190,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
creds->type);
goto error;
}
+ sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */
resolved = grpc_blocking_resolve_address(addr, "https");
@@ -205,9 +204,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
}
for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ grpc_tcp_listener *listener;
+ listener = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
+ port_temp = grpc_tcp_listener_get_port(listener);
if (port_temp >= 0) {
if (port_num == -1) {
port_num = port_temp;
diff --git a/src/core/support/avl.c b/src/core/support/avl.c
new file mode 100644
index 0000000000..9734c9987f
--- /dev/null
+++ b/src/core/support/avl.c
@@ -0,0 +1,288 @@
+/*
+ *
+ * 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 <grpc/support/avl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) {
+ gpr_avl out;
+ out.vtable = vtable;
+ out.root = NULL;
+ return out;
+}
+
+static gpr_avl_node *ref_node(gpr_avl_node *node) {
+ if (node) {
+ gpr_ref(&node->refs);
+ }
+ return node;
+}
+
+static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) {
+ if (node == NULL) {
+ return;
+ }
+ if (gpr_unref(&node->refs)) {
+ vtable->destroy_key(node->key);
+ vtable->destroy_value(node->value);
+ unref_node(vtable, node->left);
+ unref_node(vtable, node->right);
+ gpr_free(node);
+ }
+}
+
+static long node_height(gpr_avl_node *node) {
+ return node == NULL ? 0 : node->height;
+}
+
+#ifndef NDEBUG
+static long calculate_height(gpr_avl_node *node) {
+ return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left),
+ calculate_height(node->right));
+}
+
+static gpr_avl_node *assert_invariants(gpr_avl_node *n) {
+ if (n == NULL) return NULL;
+ assert_invariants(n->left);
+ assert_invariants(n->right);
+ assert(calculate_height(n) == n->height);
+ assert(labs(node_height(n->left) - node_height(n->right)) <= 1);
+ return n;
+}
+#else
+static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; }
+#endif
+
+gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ gpr_avl_node *node = gpr_malloc(sizeof(*node));
+ gpr_ref_init(&node->refs, 1);
+ node->key = key;
+ node->value = value;
+ node->left = assert_invariants(left);
+ node->right = assert_invariants(right);
+ node->height = 1 + GPR_MAX(node_height(left), node_height(right));
+ return node;
+}
+
+static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node,
+ void *key) {
+ long cmp;
+
+ if (node == NULL) {
+ return NULL;
+ }
+
+ cmp = vtable->compare_keys(node->key, key);
+ if (cmp == 0) {
+ return node;
+ } else if (cmp > 0) {
+ return get(vtable, node->left, key);
+ } else {
+ return get(vtable, node->right, key);
+ }
+}
+
+void *gpr_avl_get(gpr_avl avl, void *key) {
+ gpr_avl_node *node = get(avl.vtable, avl.root, key);
+ return node ? node->value : NULL;
+}
+
+static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
+ void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ gpr_avl_node *n =
+ new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
+ new_node(key, value, left, ref_node(right->left)),
+ ref_node(right->right));
+ unref_node(vtable, right);
+ return n;
+}
+
+static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
+ void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ gpr_avl_node *n = new_node(
+ vtable->copy_key(left->key), vtable->copy_value(left->value),
+ ref_node(left->left), new_node(key, value, ref_node(left->right), right));
+ unref_node(vtable, left);
+ return n;
+}
+
+static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
+ void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ /* rotate_right(..., rotate_left(left), right) */
+ gpr_avl_node *n = new_node(
+ vtable->copy_key(left->right->key),
+ vtable->copy_value(left->right->value),
+ new_node(vtable->copy_key(left->key), vtable->copy_value(left->value),
+ ref_node(left->left), ref_node(left->right->left)),
+ new_node(key, value, ref_node(left->right->right), right));
+ unref_node(vtable, left);
+ return n;
+}
+
+static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
+ void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ /* rotate_left(..., left, rotate_right(right)) */
+ gpr_avl_node *n = new_node(
+ vtable->copy_key(right->left->key),
+ vtable->copy_value(right->left->value),
+ new_node(key, value, left, ref_node(right->left->left)),
+ new_node(vtable->copy_key(right->key), vtable->copy_key(right->value),
+ ref_node(right->left->right), ref_node(right->right)));
+ unref_node(vtable, right);
+ return n;
+}
+
+static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
+ void *value, gpr_avl_node *left,
+ gpr_avl_node *right) {
+ switch (node_height(left) - node_height(right)) {
+ case 2:
+ if (node_height(left->left) - node_height(left->right) == -1) {
+ return assert_invariants(
+ rotate_left_right(vtable, key, value, left, right));
+ } else {
+ return assert_invariants(rotate_right(vtable, key, value, left, right));
+ }
+ case -2:
+ if (node_height(right->left) - node_height(right->right) == 1) {
+ return assert_invariants(
+ rotate_right_left(vtable, key, value, left, right));
+ } else {
+ return assert_invariants(rotate_left(vtable, key, value, left, right));
+ }
+ default:
+ return assert_invariants(new_node(key, value, left, right));
+ }
+}
+
+static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node,
+ void *key, void *value) {
+ long cmp;
+ if (node == NULL) {
+ return new_node(key, value, NULL, NULL);
+ }
+ cmp = vtable->compare_keys(node->key, key);
+ if (cmp == 0) {
+ return new_node(key, value, ref_node(node->left), ref_node(node->right));
+ } else if (cmp > 0) {
+ return rebalance(
+ vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
+ add(vtable, node->left, key, value), ref_node(node->right));
+ } else {
+ return rebalance(vtable, vtable->copy_key(node->key),
+ vtable->copy_value(node->value), ref_node(node->left),
+ add(vtable, node->right, key, value));
+ }
+}
+
+gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) {
+ gpr_avl_node *old_root = avl.root;
+ avl.root = add(avl.vtable, avl.root, key, value);
+ assert_invariants(avl.root);
+ unref_node(avl.vtable, old_root);
+ return avl;
+}
+
+static gpr_avl_node *in_order_head(gpr_avl_node *node) {
+ while (node->left != NULL) {
+ node = node->left;
+ }
+ return node;
+}
+
+static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
+ while (node->right != NULL) {
+ node = node->right;
+ }
+ return node;
+}
+
+static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node,
+ void *key) {
+ long cmp;
+ if (node == NULL) {
+ return NULL;
+ }
+ cmp = vtable->compare_keys(node->key, key);
+ if (cmp == 0) {
+ if (node->left == NULL) {
+ return ref_node(node->right);
+ } else if (node->right == NULL) {
+ return ref_node(node->left);
+ } else if (node->left->height < node->right->height) {
+ gpr_avl_node *h = in_order_head(node->right);
+ return rebalance(vtable, vtable->copy_key(h->key),
+ vtable->copy_value(h->value), ref_node(node->left),
+ remove(vtable, node->right, h->key));
+ } else {
+ gpr_avl_node *h = in_order_tail(node->left);
+ return rebalance(
+ vtable, vtable->copy_key(h->key), vtable->copy_value(h->value),
+ remove(vtable, node->left, h->key), ref_node(node->right));
+ }
+ } else if (cmp > 0) {
+ return rebalance(vtable, vtable->copy_key(node->key),
+ vtable->copy_value(node->value),
+ remove(vtable, node->left, key), ref_node(node->right));
+ } else {
+ return rebalance(vtable, vtable->copy_key(node->key),
+ vtable->copy_value(node->value), ref_node(node->left),
+ remove(vtable, node->right, key));
+ }
+}
+
+gpr_avl gpr_avl_remove(gpr_avl avl, void *key) {
+ gpr_avl_node *old_root = avl.root;
+ avl.root = remove(avl.vtable, avl.root, key);
+ assert_invariants(avl.root);
+ unref_node(avl.vtable, old_root);
+ return avl;
+}
+
+gpr_avl gpr_avl_ref(gpr_avl avl) {
+ ref_node(avl.root);
+ return avl;
+}
+
+void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); }
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
index 53024e88f1..5b091f17b0 100644
--- a/src/core/support/slice.c
+++ b/src/core/support/slice.c
@@ -57,6 +57,21 @@ void gpr_slice_unref(gpr_slice slice) {
}
}
+/* gpr_slice_from_static_string support structure - a refcount that does
+ nothing */
+static void noop_ref_or_unref(void *unused) {}
+
+static gpr_slice_refcount noop_refcount = {noop_ref_or_unref,
+ noop_ref_or_unref};
+
+gpr_slice gpr_slice_from_static_string(const char *s) {
+ gpr_slice slice;
+ slice.refcount = &noop_refcount;
+ slice.data.refcounted.bytes = (gpr_uint8 *)s;
+ slice.data.refcounted.length = strlen(s);
+ return slice;
+}
+
/* gpr_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
index c36d94d044..653a1c88c1 100644
--- a/src/core/support/thd_posix.c
+++ b/src/core/support/thd_posix.c
@@ -53,7 +53,7 @@ struct thd_arg {
/* Body of every thread started via gpr_thd_new. */
static void *thread_body(void *v) {
struct thd_arg a = *(struct thd_arg *)v;
- gpr_free(v);
+ free(v);
(*a.body)(a.arg);
return NULL;
}
@@ -63,7 +63,10 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
int thread_started;
pthread_attr_t attr;
pthread_t p;
- struct thd_arg *a = gpr_malloc(sizeof(*a));
+ /* don't use gpr_malloc as we may cause an infinite recursion with
+ * the profiling code */
+ struct thd_arg *a = malloc(sizeof(*a));
+ GPR_ASSERT(a != NULL);
a->body = thd_body;
a->arg = arg;
@@ -78,7 +81,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!thread_started) {
- gpr_free(a);
+ free(a);
}
*t = (gpr_thd_id)p;
return thread_started;
diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c
index 9f830df68c..57417f41b0 100644
--- a/src/core/surface/byte_buffer_reader.c
+++ b/src/core/surface/byte_buffer_reader.c
@@ -121,4 +121,3 @@ gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
}
return out_slice;
}
-
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index aa435d44d3..4affafa585 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -43,6 +43,7 @@
#include <grpc/support/useful.h>
#include "src/core/channel/channel_stack.h"
+#include "src/core/compression/algorithm_metadata.h"
#include "src/core/iomgr/timer.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
@@ -50,6 +51,7 @@
#include "src/core/surface/call.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/completion_queue.h"
+#include "src/core/transport/static_metadata.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
@@ -135,7 +137,6 @@ struct grpc_call {
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
- grpc_mdctx *metadata_context;
/* TODO(ctiller): share with cq if possible? */
gpr_mu mu;
@@ -267,7 +268,6 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
}
call->send_deadline = send_deadline;
GRPC_CHANNEL_INTERNAL_REF(channel, "call");
- call->metadata_context = grpc_channel_get_metadata_context(channel);
/* initial refcount dropped by grpc_call_destroy */
grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
call->context, server_transport_data,
@@ -567,9 +567,8 @@ static int prepare_application_metadata(grpc_call *call, int count,
grpc_metadata *md = &metadata[i];
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(call->metadata_context, md->key,
- (const gpr_uint8 *)md->value,
- md->value_length);
+ l->md = grpc_mdelem_from_string_and_buffer(
+ md->key, (const gpr_uint8 *)md->value, md->value_length);
if (!grpc_mdstr_is_legal_header(l->md->key)) {
gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
grpc_mdstr_as_c_string(l->md->key));
@@ -712,8 +711,7 @@ static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description) {
grpc_mdstr *details =
- description ? grpc_mdstr_from_string(c->metadata_context, description)
- : NULL;
+ description ? grpc_mdstr_from_string(description) : NULL;
cancel_closure *cc = gpr_malloc(sizeof(*cc));
GPR_ASSERT(status != GRPC_STATUS_OK);
@@ -788,8 +786,12 @@ static void destroy_status(void *ignored) {}
static gpr_uint32 decode_status(grpc_mdelem *md) {
gpr_uint32 status;
- void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
- if (user_data) {
+ 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;
+ user_data = grpc_mdelem_get_user_data(md, destroy_status);
+ if (user_data != NULL) {
status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
} else {
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
@@ -803,38 +805,23 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
return status;
}
-/* just as for status above, we need to offset: metadata userdata can't hold a
- * zero (null), which in this case is used to signal no compression */
-#define COMPRESS_OFFSET 1
-static void destroy_compression(void *ignored) {}
-
static gpr_uint32 decode_compression(grpc_mdelem *md) {
- grpc_compression_algorithm algorithm;
- void *user_data = grpc_mdelem_get_user_data(md, destroy_compression);
- if (user_data) {
- algorithm =
- ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET;
- } else {
+ grpc_compression_algorithm algorithm =
+ grpc_compression_algorithm_from_mdstr(md->value);
+ if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
- if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
- &algorithm)) {
- gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
- assert(0);
- }
- grpc_mdelem_set_user_data(
- md, destroy_compression,
- (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET));
+ gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
}
return algorithm;
}
static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) {
- if (elem->key == grpc_channel_get_status_string(call->channel)) {
+ 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_channel_get_message_string(call->channel)) {
+ } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
GPR_TIMER_BEGIN("status-details", 0);
set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value));
GPR_TIMER_END("status-details", 0);
@@ -867,14 +854,12 @@ static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
elem = recv_common_filter(call, elem);
if (elem == NULL) {
return NULL;
- } else if (elem->key ==
- grpc_channel_get_compression_algorithm_string(call->channel)) {
+ } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
GPR_TIMER_BEGIN("compression_algorithm", 0);
set_compression_algorithm(call, decode_compression(elem));
GPR_TIMER_END("compression_algorithm", 0);
return NULL;
- } else if (elem->key == grpc_channel_get_encodings_accepted_by_peer_string(
- call->channel)) {
+ } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
set_encodings_accepted_by_peer(call, elem);
GPR_TIMER_END("encodings_accepted_by_peer", 0);
@@ -922,11 +907,12 @@ static batch_control *allocate_batch_control(grpc_call *call) {
size_t i;
for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
if ((call->used_batches & (1 << i)) == 0) {
- call->used_batches |= (gpr_uint8)(1 << i);
+ call->used_batches =
+ (gpr_uint8)(call->used_batches | (gpr_uint8)(1 << i));
return &call->active_batches[i];
}
}
- GPR_UNREACHABLE_CODE(return NULL);
+ return NULL;
}
static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -1240,10 +1226,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *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(
- call->metadata_context,
- GRPC_MDSTR_REF(grpc_channel_get_message_string(call->channel)),
+ GRPC_MDSTR_GRPC_MESSAGE,
grpc_mdstr_from_string(
- call->metadata_context,
op->data.send_status_from_server.status_details));
call->send_extra_metadata_count++;
set_status_details(
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index a9a5f828f2..859197412b 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -46,6 +46,7 @@
#include "src/core/surface/api_trace.h"
#include "src/core/surface/call.h"
#include "src/core/surface/init.h"
+#include "src/core/transport/static_metadata.h"
/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
* Avoids needing to take a metadata context lock for sending status
@@ -64,17 +65,7 @@ struct grpc_channel {
int is_client;
gpr_refcount refs;
gpr_uint32 max_message_length;
- grpc_mdctx *metadata_context;
- /** mdstr for the grpc-status key */
- grpc_mdstr *grpc_status_string;
- grpc_mdstr *grpc_compression_algorithm_string;
- grpc_mdstr *grpc_encodings_accepted_by_peer_string;
- grpc_mdstr *grpc_message_string;
- grpc_mdstr *path_string;
- grpc_mdstr *authority_string;
grpc_mdelem *default_authority;
- /** mdelem for grpc-status: 0 thru grpc-status: 2 */
- grpc_mdelem *grpc_status_elem[NUM_CACHED_STATUS_ELEMS];
gpr_mu registered_call_mu;
registered_call *registered_calls;
@@ -93,7 +84,7 @@ struct grpc_channel {
grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t num_filters,
- const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) {
+ const grpc_channel_args *args, int is_client) {
size_t i;
size_t size =
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
@@ -104,22 +95,6 @@ grpc_channel *grpc_channel_create_from_filters(
channel->is_client = is_client;
/* decremented by grpc_channel_destroy */
gpr_ref_init(&channel->refs, 1);
- channel->metadata_context = mdctx;
- channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
- channel->grpc_compression_algorithm_string =
- grpc_mdstr_from_string(mdctx, "grpc-encoding");
- channel->grpc_encodings_accepted_by_peer_string =
- grpc_mdstr_from_string(mdctx, "grpc-accept-encoding");
- channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
- for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
- char buf[GPR_LTOA_MIN_BUFSIZE];
- gpr_ltoa((long)i, buf);
- channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
- mdctx, GRPC_MDSTR_REF(channel->grpc_status_string),
- grpc_mdstr_from_string(mdctx, buf));
- }
- channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
- channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
@@ -146,7 +121,7 @@ grpc_channel *grpc_channel_create_from_filters(
GRPC_MDELEM_UNREF(channel->default_authority);
}
channel->default_authority = grpc_mdelem_from_strings(
- mdctx, ":authority", args->args[i].value.string);
+ ":authority", args->args[i].value.string);
}
} else if (0 ==
strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
@@ -160,7 +135,7 @@ grpc_channel *grpc_channel_create_from_filters(
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
channel->default_authority = grpc_mdelem_from_strings(
- mdctx, ":authority", args->args[i].value.string);
+ ":authority", args->args[i].value.string);
}
}
}
@@ -171,14 +146,13 @@ grpc_channel *grpc_channel_create_from_filters(
target != NULL) {
char *default_authority = grpc_get_default_authority(target);
if (default_authority) {
- channel->default_authority = grpc_mdelem_from_strings(
- channel->metadata_context, ":authority", default_authority);
+ channel->default_authority =
+ grpc_mdelem_from_strings(":authority", default_authority);
}
gpr_free(default_authority);
}
grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args,
- channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel));
return channel;
@@ -227,13 +201,10 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, cq,
- grpc_mdelem_from_metadata_strings(
- channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
- grpc_mdstr_from_string(channel->metadata_context, method)),
- host ? grpc_mdelem_from_metadata_strings(
- channel->metadata_context,
- GRPC_MDSTR_REF(channel->authority_string),
- grpc_mdstr_from_string(channel->metadata_context, host))
+ grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method)),
+ host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
+ grpc_mdstr_from_string(host))
: NULL,
deadline);
}
@@ -245,15 +216,11 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
"grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
4, (channel, method, host, reserved));
GPR_ASSERT(!reserved);
- rc->path = grpc_mdelem_from_metadata_strings(
- channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
- grpc_mdstr_from_string(channel->metadata_context, method));
- rc->authority =
- host ? grpc_mdelem_from_metadata_strings(
- channel->metadata_context,
- GRPC_MDSTR_REF(channel->authority_string),
- grpc_mdstr_from_string(channel->metadata_context, host))
- : NULL;
+ rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method));
+ rc->authority = host ? grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host))
+ : NULL;
gpr_mu_lock(&channel->registered_call_mu);
rc->next = channel->registered_calls;
channel->registered_calls = rc;
@@ -293,17 +260,7 @@ void grpc_channel_internal_ref(grpc_channel *c) {
}
static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
- size_t i;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
- for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
- GRPC_MDELEM_UNREF(channel->grpc_status_elem[i]);
- }
- GRPC_MDSTR_UNREF(channel->grpc_status_string);
- GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string);
- GRPC_MDSTR_UNREF(channel->grpc_encodings_accepted_by_peer_string);
- GRPC_MDSTR_UNREF(channel->grpc_message_string);
- GRPC_MDSTR_UNREF(channel->path_string);
- GRPC_MDSTR_UNREF(channel->authority_string);
while (channel->registered_calls) {
registered_call *rc = channel->registered_calls;
channel->registered_calls = rc->next;
@@ -316,7 +273,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
if (channel->default_authority != NULL) {
GRPC_MDELEM_UNREF(channel->default_authority);
}
- grpc_mdctx_unref(channel->metadata_context);
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
@@ -355,38 +311,19 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
-grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel) {
- return channel->metadata_context;
-}
-
-grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
- return channel->grpc_status_string;
-}
-
-grpc_mdstr *grpc_channel_get_compression_algorithm_string(
- grpc_channel *channel) {
- return channel->grpc_compression_algorithm_string;
-}
-
-grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
- grpc_channel *channel) {
- return channel->grpc_encodings_accepted_by_peer_string;
-}
-
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
- if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
- return GRPC_MDELEM_REF(channel->grpc_status_elem[i]);
- } else {
- char tmp[GPR_LTOA_MIN_BUFSIZE];
- gpr_ltoa(i, tmp);
- return grpc_mdelem_from_metadata_strings(
- channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string),
- grpc_mdstr_from_string(channel->metadata_context, tmp));
+ char tmp[GPR_LTOA_MIN_BUFSIZE];
+ switch (i) {
+ case 0:
+ return GRPC_MDELEM_GRPC_STATUS_0;
+ case 1:
+ return GRPC_MDELEM_GRPC_STATUS_1;
+ case 2:
+ return GRPC_MDELEM_GRPC_STATUS_2;
}
-}
-
-grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) {
- return channel->grpc_message_string;
+ gpr_ltoa(i, tmp);
+ return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
+ grpc_mdstr_from_string(tmp));
}
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) {
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index e5030d52d2..7dea609ebc 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -40,26 +40,17 @@
grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t count,
- const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client);
+ const grpc_channel_args *args, int is_client);
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
-/** Get a (borrowed) pointer to the channel wide metadata context */
-grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
-
/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
status_code.
The returned elem is owned by the caller. */
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
int status_code);
-grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
-grpc_mdstr *grpc_channel_get_compression_algorithm_string(
- grpc_channel *channel);
-grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
- grpc_channel *channel);
-grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 51d9130b63..aceb932742 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -37,6 +37,8 @@
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
#include "src/core/census/grpc_filter.h"
#include "src/core/channel/channel_args.h"
@@ -56,11 +58,11 @@ typedef struct {
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
+ grpc_closure initial_string_sent;
+ gpr_slice_buffer initial_string_buffer;
grpc_endpoint *tcp;
- grpc_mdctx *mdctx;
-
grpc_closure connected;
} connector;
@@ -72,18 +74,33 @@ static void connector_ref(grpc_connector *con) {
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
- grpc_mdctx_unref(c->mdctx);
+ /* c->initial_string_buffer does not need to be destroyed */
gpr_free(c);
}
}
+static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
+ int success) {
+ connector_unref(exec_ctx, arg);
+}
+
static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->tcp;
if (tcp != NULL) {
- c->result->transport = grpc_create_chttp2_transport(
- exec_ctx, c->args.channel_args, tcp, c->mdctx, 1);
+ if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
+ grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
+ c);
+ gpr_slice_buffer_init(&c->initial_string_buffer);
+ gpr_slice_buffer_add(&c->initial_string_buffer,
+ c->args.initial_connect_string);
+ connector_ref(arg);
+ grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
+ &c->initial_string_sent);
+ }
+ c->result->transport =
+ grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
GPR_ASSERT(c->result->transport);
@@ -123,7 +140,6 @@ static const grpc_connector_vtable connector_vtable = {
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
- grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel *master;
} subchannel_factory;
@@ -139,7 +155,6 @@ static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
if (gpr_unref(&f->refs)) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
- grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
@@ -154,10 +169,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
grpc_subchannel *s;
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
- c->mdctx = f->mdctx;
- grpc_mdctx_ref(c->mdctx);
gpr_ref_init(&c->refs, 1);
- args->mdctx = f->mdctx;
args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
@@ -182,7 +194,6 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
const grpc_channel_filter *filters[MAX_FILTERS];
grpc_resolver *resolver;
subchannel_factory *f;
- grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0;
GRPC_API_TRACE(
@@ -196,14 +207,12 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
- channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
- args, mdctx, 1);
+ channel =
+ grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
- grpc_mdctx_ref(mdctx);
- f->mdctx = mdctx;
f->merge_args = grpc_channel_args_copy(args);
f->master = channel;
GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index f8cba01cad..04d68620f1 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -93,6 +93,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
+ grpc_mdctx_global_init();
grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
@@ -147,6 +148,7 @@ void grpc_shutdown(void) {
g_all_of_the_plugins[i].destroy();
}
}
+ grpc_mdctx_global_shutdown();
}
gpr_mu_unlock(&g_init_mu);
}
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index fc458a603d..4a55544ac1 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -49,7 +49,6 @@ typedef struct {
} call_data;
typedef struct {
- grpc_mdctx *mdctx;
grpc_channel *master;
grpc_status_code error_code;
const char *error_message;
@@ -60,9 +59,9 @@ static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
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(chand->mdctx, "grpc-status", tmp);
- calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message",
- chand->error_message);
+ calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
+ calld->details.md =
+ grpc_mdelem_from_strings("grpc-message", chand->error_message);
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
@@ -115,7 +114,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data;
GPR_ASSERT(args->is_first);
GPR_ASSERT(args->is_last);
- chand->mdctx = args->metadata_context;
chand->master = args->master;
}
@@ -139,8 +137,8 @@ grpc_channel *grpc_lame_client_channel_create(const char *target,
channel_data *chand;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
static const grpc_channel_filter *filters[] = {&lame_filter};
- channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, 1,
- NULL, grpc_mdctx_create(), 1);
+ channel =
+ grpc_channel_create_from_filters(&exec_ctx, target, filters, 1, NULL, 1);
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
GRPC_API_TRACE(
"grpc_lame_client_channel_create(target=%s, error_code=%d, "
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index e07f04e8fe..c9a54d9237 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -37,6 +37,8 @@
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
#include "src/core/census/grpc_filter.h"
#include "src/core/channel/channel_args.h"
@@ -61,14 +63,14 @@ typedef struct {
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
+ grpc_closure initial_string_sent;
+ gpr_slice_buffer initial_string_buffer;
gpr_mu mu;
grpc_endpoint *connecting_endpoint;
grpc_endpoint *newly_connecting_endpoint;
grpc_closure connected_closure;
-
- grpc_mdctx *mdctx;
} connector;
static void connector_ref(grpc_connector *con) {
@@ -79,7 +81,7 @@ static void connector_ref(grpc_connector *con) {
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
- grpc_mdctx_unref(c->mdctx);
+ /* c->initial_string_buffer does not need to be destroyed */
gpr_free(c);
}
}
@@ -102,7 +104,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
c->result->transport = grpc_create_chttp2_transport(
- exec_ctx, c->args.channel_args, secure_endpoint, c->mdctx, 1);
+ exec_ctx, c->args.channel_args, secure_endpoint, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
@@ -115,6 +117,14 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
notify->cb(exec_ctx, notify->cb_arg, 1);
}
+static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
+ int success) {
+ connector *c = arg;
+ grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base,
+ c->connecting_endpoint,
+ on_secure_handshake_done, c);
+}
+
static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
connector *c = arg;
grpc_closure *notify;
@@ -124,8 +134,19 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
GPR_ASSERT(c->connecting_endpoint == NULL);
c->connecting_endpoint = tcp;
gpr_mu_unlock(&c->mu);
- grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base,
- tcp, on_secure_handshake_done, c);
+ if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
+ grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
+ c);
+ gpr_slice_buffer_init(&c->initial_string_buffer);
+ gpr_slice_buffer_add(&c->initial_string_buffer,
+ c->args.initial_connect_string);
+ grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
+ &c->initial_string_sent);
+ } else {
+ grpc_security_connector_do_handshake(exec_ctx,
+ &c->security_connector->base, tcp,
+ on_secure_handshake_done, c);
+ }
} else {
memset(c->result, 0, sizeof(*c->result));
notify = c->notify;
@@ -171,7 +192,6 @@ static const grpc_connector_vtable connector_vtable = {
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
- grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel_security_connector *security_connector;
grpc_channel *master;
@@ -190,7 +210,6 @@ static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
"subchannel_factory");
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
- grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
@@ -206,13 +225,10 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
c->security_connector = f->security_connector;
- c->mdctx = f->mdctx;
gpr_mu_init(&c->mu);
- grpc_mdctx_ref(c->mdctx);
gpr_ref_init(&c->refs, 1);
args->args = final_args;
args->master = f->master;
- args->mdctx = f->mdctx;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args);
@@ -236,7 +252,6 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
grpc_channel_args *args_copy;
grpc_channel_args *new_args_from_connector;
grpc_channel_security_connector *security_connector;
- grpc_mdctx *mdctx;
grpc_resolver *resolver;
subchannel_factory *f;
#define MAX_FILTERS 3
@@ -266,7 +281,6 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
target, GRPC_STATUS_INVALID_ARGUMENT,
"Failed to create security connector.");
}
- mdctx = grpc_mdctx_create();
connector_arg = grpc_security_connector_to_arg(&security_connector->base);
args_copy = grpc_channel_args_copy_and_add(
@@ -280,13 +294,11 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
- args_copy, mdctx, 1);
+ args_copy, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
- grpc_mdctx_ref(mdctx);
- f->mdctx = mdctx;
GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory");
f->security_connector = security_connector;
f->merge_args = grpc_channel_args_copy(args_copy);
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index e9f380083f..cdbd542d9a 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -54,6 +54,7 @@
#include "src/core/surface/completion_queue.h"
#include "src/core/surface/init.h"
#include "src/core/transport/metadata.h"
+#include "src/core/transport/static_metadata.h"
typedef struct listener {
void *arg;
@@ -108,8 +109,6 @@ struct channel_data {
grpc_server *server;
grpc_connectivity_state connectivity_state;
grpc_channel *channel;
- grpc_mdstr *path_key;
- grpc_mdstr *authority_key;
/* linked list of all channels on a server */
channel_data *next;
channel_data *prev;
@@ -558,12 +557,11 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
- channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
- if (md->key == chand->path_key) {
+ if (md->key == GRPC_MDSTR_PATH) {
calld->path = GRPC_MDSTR_REF(md->value);
return NULL;
- } else if (md->key == chand->authority_key) {
+ } else if (md->key == GRPC_MDSTR_AUTHORITY) {
calld->host = GRPC_MDSTR_REF(md->value);
return NULL;
}
@@ -718,9 +716,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(!args->is_last);
chand->server = NULL;
chand->channel = NULL;
- chand->path_key = grpc_mdstr_from_string(args->metadata_context, ":path");
- chand->authority_key =
- grpc_mdstr_from_string(args->metadata_context, ":authority");
chand->next = chand->prev = chand;
chand->registered_methods = NULL;
chand->connectivity_state = GRPC_CHANNEL_IDLE;
@@ -750,8 +745,6 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
chand->next = chand->prev = chand;
maybe_finish_shutdown(exec_ctx, chand->server);
gpr_mu_unlock(&chand->server->mu_global);
- GRPC_MDSTR_UNREF(chand->path_key);
- GRPC_MDSTR_UNREF(chand->authority_key);
server_unref(exec_ctx, chand->server);
}
}
@@ -894,7 +887,7 @@ void grpc_server_start(grpc_server *server) {
void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
grpc_transport *transport,
grpc_channel_filter const **extra_filters,
- size_t num_extra_filters, grpc_mdctx *mdctx,
+ size_t num_extra_filters,
const grpc_channel_args *args) {
size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
grpc_channel_filter const **filters =
@@ -929,7 +922,7 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
}
channel = grpc_channel_create_from_filters(exec_ctx, NULL, filters,
- num_filters, args, mdctx, 0);
+ num_filters, args, 0);
chand = (channel_data *)grpc_channel_stack_element(
grpc_channel_get_channel_stack(channel), 0)->channel_data;
chand->server = s;
@@ -948,8 +941,8 @@ 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(mdctx, rm->host) : NULL;
- method = grpc_mdstr_from_string(mdctx, rm->method);
+ 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);
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != NULL;
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index 4c46d07679..a957fdb360 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -57,7 +57,7 @@ void grpc_server_add_listener(
void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server,
grpc_transport *transport,
grpc_channel_filter const **extra_filters,
- size_t num_extra_filters, grpc_mdctx *mdctx,
+ size_t num_extra_filters,
const grpc_channel_args *args);
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 580b91573c..990bc4aa23 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -44,11 +44,11 @@
#include <grpc/support/useful.h>
static void setup_transport(grpc_exec_ctx *exec_ctx, void *server,
- grpc_transport *transport, grpc_mdctx *mdctx) {
+ grpc_transport *transport) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_server_filter};
grpc_server_setup_transport(exec_ctx, server, transport, extra_filters,
- GPR_ARRAY_SIZE(extra_filters), mdctx,
+ GPR_ARRAY_SIZE(extra_filters),
grpc_server_get_channel_args(server));
}
@@ -61,10 +61,9 @@ static void new_transport(grpc_exec_ctx *exec_ctx, void *server,
* (as in server_secure_chttp2.c) needs to add synchronization to avoid this
* case.
*/
- grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_transport *transport = grpc_create_chttp2_transport(
- exec_ctx, grpc_server_get_channel_args(server), tcp, mdctx, 0);
- setup_transport(exec_ctx, server, transport, mdctx);
+ exec_ctx, grpc_server_get_channel_args(server), tcp, 0);
+ setup_transport(exec_ctx, server, transport);
grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
}
@@ -107,9 +106,11 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ grpc_tcp_listener *listener;
+ listener = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
+ port_temp = grpc_tcp_listener_get_port(listener);
if (port_temp >= 0) {
if (port_num == -1) {
port_num = port_temp;
diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c
index 6c7c00b7c3..28d5433d15 100644
--- a/src/core/transport/chttp2/hpack_encoder.c
+++ b/src/core/transport/chttp2/hpack_encoder.c
@@ -36,12 +36,15 @@
#include <assert.h>
#include <string.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
+
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/chttp2/hpack_table.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
#include "src/core/transport/chttp2/varint.h"
+#include "src/core/transport/static_metadata.h"
#define HASH_FRAGMENT_1(x) ((x)&255)
#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
@@ -154,6 +157,18 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, size_t len) {
return gpr_slice_buffer_tiny_add(st->output, len);
}
+static void evict_entry(grpc_chttp2_hpack_compressor *c) {
+ c->tail_remote_index++;
+ GPR_ASSERT(c->tail_remote_index > 0);
+ GPR_ASSERT(c->table_size >=
+ c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
+ GPR_ASSERT(c->table_elems > 0);
+ c->table_size = (gpr_uint16)(
+ c->table_size -
+ c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
+ c->table_elems--;
+}
+
/* add an element to the decoder table */
static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
gpr_uint32 key_hash = elem->key->hash;
@@ -164,26 +179,21 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
GPR_ASSERT(elem_size < 65536);
+ if (elem_size > c->max_table_size) {
+ while (c->table_size > 0) {
+ evict_entry(c);
+ }
+ return;
+ }
+
/* Reserve space for this element in the remote table: if this overflows
the current table, drop elements until it fits, matching the decompressor
algorithm */
- /* TODO(ctiller): constant */
- while (c->table_size + elem_size > 4096) {
- c->tail_remote_index++;
- GPR_ASSERT(c->tail_remote_index > 0);
- GPR_ASSERT(c->table_size >=
- c->table_elem_size[c->tail_remote_index %
- GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
- GPR_ASSERT(c->table_elems > 0);
- c->table_size =
- (gpr_uint16)(c->table_size -
- c->table_elem_size[c->tail_remote_index %
- GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
- c->table_elems--;
+ while (c->table_size + elem_size > c->max_table_size) {
+ evict_entry(c);
}
- GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS);
- c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] =
- (gpr_uint16)elem_size;
+ GPR_ASSERT(c->table_elems < c->max_table_size);
+ c->table_elem_size[new_index % c->cap_table_elems] = (gpr_uint16)elem_size;
c->table_size = (gpr_uint16)(c->table_size + elem_size);
c->table_elems++;
@@ -329,6 +339,14 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
add_header_data(st, gpr_slice_ref(value_slice));
}
+static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
+ framer_state *st) {
+ gpr_uint32 len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
+ GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
+ add_tiny_header_data(st, len), len);
+ c->advertise_table_size_change = 0;
+}
+
static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c,
gpr_uint32 elem_index) {
return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
@@ -435,8 +453,7 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
grpc_chttp2_encode_timeout(
gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
mdelem = grpc_mdelem_from_metadata_strings(
- c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
- grpc_mdstr_from_string(c->mdctx, timeout_str));
+ GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
hpack_enc(c, mdelem, st);
GRPC_MDELEM_UNREF(mdelem);
}
@@ -447,11 +464,20 @@ gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
return slice;
}
-void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
- grpc_mdctx *ctx) {
+static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) {
+ return (bytes + 31) / 32;
+}
+
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
memset(c, 0, sizeof(*c));
- c->mdctx = ctx;
- c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
+ c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
+ c->cap_table_elems = elems_for_bytes(c->max_table_size);
+ c->max_table_elems = c->cap_table_elems;
+ c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
+ c->table_elem_size =
+ 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);
}
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
@@ -460,7 +486,55 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]);
if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
}
- GRPC_MDSTR_UNREF(c->timeout_key_str);
+ gpr_free(c->table_elem_size);
+}
+
+void grpc_chttp2_hpack_compressor_set_max_usable_size(
+ grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
+ c->max_usable_size = max_table_size;
+ grpc_chttp2_hpack_compressor_set_max_table_size(
+ c, GPR_MIN(c->max_table_size, max_table_size));
+}
+
+static void rebuild_elems(grpc_chttp2_hpack_compressor *c, gpr_uint32 new_cap) {
+ gpr_uint16 *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
+ gpr_uint32 i;
+
+ memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
+ GPR_ASSERT(c->table_elems <= new_cap);
+
+ for (i = 0; i < c->table_elems; i++) {
+ gpr_uint32 ofs = c->tail_remote_index + i + 1;
+ table_elem_size[ofs % new_cap] =
+ c->table_elem_size[ofs % c->cap_table_elems];
+ }
+
+ c->cap_table_elems = new_cap;
+ gpr_free(c->table_elem_size);
+ c->table_elem_size = table_elem_size;
+}
+
+void grpc_chttp2_hpack_compressor_set_max_table_size(
+ grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
+ max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
+ if (max_table_size == c->max_table_size) {
+ return;
+ }
+ while (c->table_size > 0 && c->table_size > max_table_size) {
+ evict_entry(c);
+ }
+ c->max_table_size = max_table_size;
+ c->max_table_elems = elems_for_bytes(max_table_size);
+ if (c->max_table_elems > c->cap_table_elems) {
+ rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
+ } else if (c->max_table_elems < c->cap_table_elems / 3) {
+ gpr_uint32 new_cap = GPR_MAX(c->max_table_elems, 16);
+ if (new_cap != c->cap_table_elems) {
+ rebuild_elems(c, new_cap);
+ }
+ }
+ c->advertise_table_size_change = 1;
+ gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
}
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
@@ -483,6 +557,9 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
updated). After this loop, we'll do a batch unref of elements. */
begin_frame(&st);
+ if (c->advertise_table_size_change != 0) {
+ emit_advertise_table_size_change(c, &st);
+ }
grpc_metadata_batch_assert_ok(metadata);
for (l = metadata->list.head; l; l = l->next) {
hpack_enc(c, l->md, &st);
diff --git a/src/core/transport/chttp2/hpack_encoder.h b/src/core/transport/chttp2/hpack_encoder.h
index 59b122dfda..a3600436e9 100644
--- a/src/core/transport/chttp2/hpack_encoder.h
+++ b/src/core/transport/chttp2/hpack_encoder.h
@@ -43,14 +43,26 @@
#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
-#define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32)
+/* initial table size, per spec */
+#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096
+/* maximum table size we'll actually use */
+#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
typedef struct {
gpr_uint32 filter_elems_sum;
+ gpr_uint32 max_table_size;
+ gpr_uint32 max_table_elems;
+ gpr_uint32 cap_table_elems;
+ /** if non-zero, advertise to the decoder that we'll start using a table
+ of this size */
+ gpr_uint8 advertise_table_size_change;
+ /** maximum number of bytes we'll use for the decode table (to guard against
+ peers ooming us by setting decode table size high) */
+ gpr_uint32 max_usable_size;
/* one before the lowest usable table index */
gpr_uint32 tail_remote_index;
- gpr_uint16 table_size;
- gpr_uint16 table_elems;
+ gpr_uint32 table_size;
+ gpr_uint32 table_elems;
/* filter tables for elems: this tables provides an approximate
popularity count for particular hashes, and are used to determine whether
@@ -59,11 +71,6 @@ typedef struct {
been seen. When that count reaches max (255), all values are halved. */
gpr_uint8 filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS];
- /* metadata context */
- grpc_mdctx *mdctx;
- /* the string 'grpc-timeout' */
- grpc_mdstr *timeout_key_str;
-
/* 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];
@@ -71,12 +78,15 @@ typedef struct {
gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
- gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
+ gpr_uint16 *table_elem_size;
} grpc_chttp2_hpack_compressor;
-void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
- grpc_mdctx *mdctx);
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c);
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
+void grpc_chttp2_hpack_compressor_set_max_table_size(
+ grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
+void grpc_chttp2_hpack_compressor_set_max_usable_size(
+ grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, gpr_uint32 id,
grpc_metadata_batch *metadata, int is_eof,
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index 6eebfc3ce4..d38ff68754 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -74,6 +74,8 @@ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end);
static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end);
+static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+ const gpr_uint8 *end);
static int parse_string_prefix(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end);
@@ -156,7 +158,7 @@ static const grpc_chttp2_hpack_parser_state first_byte_action[] = {
parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx,
parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx,
parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size,
- parse_max_tbl_size_x, parse_error};
+ parse_max_tbl_size_x, parse_illegal_op};
/* indexes the first byte to a parse state function - generated by
gen_hpack_tables.c */
@@ -169,7 +171,7 @@ static const gpr_uint8 first_byte_lut[256] = {
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
- ILLEGAL, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
+ MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
@@ -622,19 +624,20 @@ static const gpr_uint8 inverse_base64[256] = {
};
/* emission helpers */
-static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
- int add_to_table) {
+static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
+ int add_to_table) {
if (add_to_table) {
- GRPC_MDELEM_REF(md);
- grpc_chttp2_hptbl_add(&p->table, md);
+ if (!grpc_chttp2_hptbl_add(&p->table, md)) {
+ return 0;
+ }
}
p->on_header(p->on_header_user_data, md);
+ return 1;
}
static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
grpc_chttp2_hpack_parser_string *str) {
- grpc_mdstr *s = grpc_mdstr_from_buffer(p->table.mdctx, (gpr_uint8 *)str->str,
- str->length);
+ grpc_mdstr *s = grpc_mdstr_from_buffer((gpr_uint8 *)str->str, str->length);
str->length = 0;
return s;
}
@@ -714,9 +717,12 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ if (md == NULL) {
+ gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
+ return 0;
+ }
GRPC_MDELEM_REF(md);
- on_hdr(p, md, 0);
- return parse_begin(p, cur, end);
+ return on_hdr(p, md, 0) && parse_begin(p, cur, end);
}
/* parse an indexed field with index < 127 */
@@ -742,21 +748,19 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 1);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 1) &&
+ parse_begin(p, cur, end);
}
/* finish a literal header with incremental indexing with no index */
static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- take_string(p, &p->key),
- take_string(p, &p->value)),
- 1);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 1) &&
+ parse_begin(p, cur, end);
}
/* parse a literal header with incremental indexing; index < 63 */
@@ -795,21 +799,19 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0) &&
+ parse_begin(p, cur, end);
}
/* finish a literal header without incremental indexing with index = 0 */
static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- take_string(p, &p->key),
- take_string(p, &p->value)),
- 0);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0) &&
+ parse_begin(p, cur, end);
}
/* parse a literal header without incremental indexing; index < 15 */
@@ -848,21 +850,19 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0) &&
+ parse_begin(p, cur, end);
}
/* finish a literal header that is never indexed with an extra value */
static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
- on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
- take_string(p, &p->key),
- take_string(p, &p->value)),
- 0);
- return parse_begin(p, cur, end);
+ return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0) &&
+ parse_begin(p, cur, end);
}
/* parse a literal header that is never indexed; index < 15 */
@@ -901,14 +901,14 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
- abort(); /* not implemented */
- return parse_begin(p, cur, end);
+ return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
+ parse_begin(p, cur, end);
}
/* parse a max table size change, max size < 15 */
static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end) {
- p->index = (*cur) & 0xf;
+ p->index = (*cur) & 0x1f;
return finish_max_tbl_size(p, cur + 1, end);
}
@@ -918,7 +918,7 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size};
p->next_state = and_then;
- p->index = 0xf;
+ p->index = 0x1f;
p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end);
}
@@ -930,6 +930,13 @@ static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
return 0;
}
+static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+ const gpr_uint8 *end) {
+ GPR_ASSERT(cur != end);
+ gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
+ return parse_error(p, cur, end);
+}
+
/* parse the 1st byte of a varint into p->parsing.value
no overflow is possible */
static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
@@ -1342,8 +1349,7 @@ static void on_header_not_set(void *user_data, grpc_mdelem *md) {
abort();
}
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
- grpc_mdctx *mdctx) {
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
p->on_header = on_header_not_set;
p->on_header_user_data = NULL;
p->state = parse_begin;
@@ -1353,7 +1359,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
p->value.str = NULL;
p->value.capacity = 0;
p->value.length = 0;
- grpc_chttp2_hptbl_init(&p->table, mdctx);
+ grpc_chttp2_hptbl_init(&p->table);
}
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index f56867016c..fb894b5735 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -95,8 +95,7 @@ struct grpc_chttp2_hpack_parser {
grpc_chttp2_hptbl table;
};
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
- grpc_mdctx *mdctx);
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
index c442c2c341..59060daad3 100644
--- a/src/core/transport/chttp2/hpack_table.c
+++ b/src/core/transport/chttp2/hpack_table.c
@@ -36,7 +36,9 @@
#include <assert.h>
#include <string.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+
#include "src/core/support/murmur_hash.h"
static struct {
@@ -169,15 +171,24 @@ static struct {
{"www-authenticate", ""},
};
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
+static gpr_uint32 entries_for_bytes(gpr_uint32 bytes) {
+ return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) /
+ GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+}
+
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) {
size_t i;
memset(tbl, 0, sizeof(*tbl));
- tbl->mdctx = mdctx;
- tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+ tbl->current_table_bytes = tbl->max_bytes =
+ GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+ tbl->max_entries = tbl->cap_entries =
+ entries_for_bytes(tbl->current_table_bytes);
+ 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(
- mdctx, static_table[i].key, static_table[i].value);
+ tbl->static_ents[i - 1] =
+ grpc_mdelem_from_strings(static_table[i].key, static_table[i].value);
}
}
@@ -187,9 +198,9 @@ void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
GRPC_MDELEM_UNREF(tbl->static_ents[i]);
}
for (i = 0; i < tbl->num_ents; i++) {
- GRPC_MDELEM_UNREF(
- tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
+ GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
}
+ gpr_free(tbl->ents);
}
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
@@ -201,8 +212,8 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
/* Otherwise, find the value in the list of valid entries */
tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
if (tbl_index < tbl->num_ents) {
- gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) %
- GRPC_CHTTP2_MAX_TABLE_COUNT;
+ gpr_uint32 offset =
+ (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries;
return tbl->ents[offset];
}
/* Invalid entry: return error */
@@ -216,21 +227,81 @@ static void evict1(grpc_chttp2_hptbl *tbl) {
GPR_SLICE_LENGTH(first_ent->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
- tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes);
- tbl->first_ent =
- (gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
+ tbl->mem_used -= (gpr_uint32)elem_bytes;
+ tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
tbl->num_ents--;
GRPC_MDELEM_UNREF(first_ent);
}
-void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+static void rebuild_ents(grpc_chttp2_hptbl *tbl, gpr_uint32 new_cap) {
+ grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
+ gpr_uint32 i;
+
+ for (i = 0; i < tbl->num_ents; i++) {
+ ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
+ }
+ gpr_free(tbl->ents);
+ tbl->ents = ents;
+ tbl->cap_entries = new_cap;
+ tbl->first_ent = 0;
+}
+
+void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+ gpr_uint32 max_bytes) {
+ if (tbl->max_bytes == max_bytes) {
+ return;
+ }
+ gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
+ while (tbl->mem_used > max_bytes) {
+ evict1(tbl);
+ }
+ tbl->max_bytes = max_bytes;
+}
+
+int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ gpr_uint32 bytes) {
+ if (tbl->current_table_bytes == bytes) {
+ return 1;
+ }
+ if (bytes > tbl->max_bytes) {
+ gpr_log(GPR_ERROR,
+ "Attempt to make hpack table %d bytes when max is %d bytes", bytes,
+ tbl->max_bytes);
+ return 0;
+ }
+ gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
+ while (tbl->mem_used > bytes) {
+ evict1(tbl);
+ }
+ tbl->current_table_bytes = bytes;
+ tbl->max_entries = entries_for_bytes(bytes);
+ if (tbl->max_entries > tbl->cap_entries) {
+ rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
+ } else if (tbl->max_entries < tbl->cap_entries / 3) {
+ gpr_uint32 new_cap = GPR_MAX(tbl->max_entries, 16u);
+ if (new_cap != tbl->cap_entries) {
+ rebuild_ents(tbl, new_cap);
+ }
+ }
+ return 1;
+}
+
+int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+ if (tbl->current_table_bytes > tbl->max_bytes) {
+ gpr_log(GPR_ERROR,
+ "HPACK max table size reduced to %d but not reflected by hpack "
+ "stream (still at %d)",
+ tbl->max_bytes, tbl->current_table_bytes);
+ return 0;
+ }
+
/* we can't add elements bigger than the max table size */
- if (elem_bytes > tbl->max_bytes) {
+ if (elem_bytes > tbl->current_table_bytes) {
/* HPACK draft 10 section 4.4 states:
* If the size of the new entry is less than or equal to the maximum
* size, that entry is added to the table. It is not an error to
@@ -243,44 +314,43 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) {
evict1(tbl);
}
- return;
+ return 1;
}
/* evict entries to ensure no overflow */
- while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) {
+ while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
evict1(tbl);
}
/* copy the finalized entry in */
- tbl->ents[tbl->last_ent] = md;
+ tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] =
+ GRPC_MDELEM_REF(md);
/* update accounting values */
- tbl->last_ent =
- (gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
tbl->num_ents++;
- tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes);
+ tbl->mem_used += (gpr_uint32)elem_bytes;
+ return 1;
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
grpc_chttp2_hptbl_find_result r = {0, 0};
- gpr_uint16 i;
+ gpr_uint32 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;
- r.index = (gpr_uint16)(i + 1);
+ r.index = i + 1u;
r.has_value = md->value == ent->value;
if (r.has_value) return r;
}
/* Scan the dynamic table */
for (i = 0; i < tbl->num_ents; i++) {
- gpr_uint16 idx =
- (gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
- grpc_mdelem *ent =
- tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
+ gpr_uint32 idx =
+ (gpr_uint32)(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;
r.index = idx;
r.has_value = md->value == ent->value;
diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h
index 4f882e2e03..a173eec30c 100644
--- a/src/core/transport/chttp2/hpack_table.h
+++ b/src/core/transport/chttp2/hpack_table.h
@@ -49,47 +49,58 @@
#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
/* Per entry overhead bytes as per the spec */
#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
+#if 0
/* Maximum number of entries we could possibly fit in the table, given defined
overheads */
#define GRPC_CHTTP2_MAX_TABLE_COUNT \
((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
+#endif
/* hpack decoder table */
typedef struct {
- grpc_mdctx *mdctx;
/* the first used entry in ents */
- gpr_uint16 first_ent;
- /* the last used entry in ents */
- gpr_uint16 last_ent;
+ gpr_uint32 first_ent;
/* how many entries are in the table */
- gpr_uint16 num_ents;
+ gpr_uint32 num_ents;
/* the amount of memory used by the table, according to the hpack algorithm */
- gpr_uint16 mem_used;
+ gpr_uint32 mem_used;
/* the max memory allowed to be used by the table, according to the hpack
algorithm */
- gpr_uint16 max_bytes;
+ gpr_uint32 max_bytes;
+ /* the currently agreed size of the table, according to the hpack algorithm */
+ gpr_uint32 current_table_bytes;
+ /* Maximum number of entries we could possibly fit in the table, given defined
+ overheads */
+ gpr_uint32 max_entries;
+ /* Number of entries allocated in ents */
+ gpr_uint32 cap_entries;
/* 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_CHTTP2_MAX_TABLE_COUNT];
+ grpc_mdelem **ents;
grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
} grpc_chttp2_hptbl;
/* initialize a hpack table */
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx);
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
+void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+ gpr_uint32 max_bytes);
+int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ gpr_uint32 bytes);
/* lookup a table entry based on its hpack index */
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
gpr_uint32 index);
/* add a table entry to the index */
-void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
+int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
+ 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 {
- gpr_uint16 index;
- gpr_uint8 has_value;
+ gpr_uint32 index;
+ 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);
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 2d0cb4abdb..3952f8a0e8 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -191,6 +191,9 @@ typedef struct {
copied to next_stream_id in parsing when parsing commences */
gpr_uint32 next_stream_id;
+ /** how far to lookahead in a stream? */
+ gpr_uint32 stream_lookahead;
+
/** last received stream id */
gpr_uint32 last_incoming_stream_id;
@@ -227,14 +230,14 @@ struct grpc_chttp2_transport_parsing {
/** was a goaway frame received? */
gpr_uint8 goaway_received;
+ /** the last sent max_table_size setting */
+ gpr_uint32 last_sent_max_table_size;
+
/** initial window change */
gpr_int64 initial_window_update;
/** data to write later - after parsing */
gpr_slice_buffer qbuf;
- /* metadata object cache */
- grpc_mdstr *str_grpc_timeout;
- grpc_mdelem *elem_grpc_status_ok;
/** parser for headers */
grpc_chttp2_hpack_parser hpack_parser;
/** simple one shot parsers */
@@ -288,7 +291,6 @@ struct grpc_chttp2_transport_parsing {
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
grpc_endpoint *ep;
- grpc_mdctx *metadata_context;
gpr_refcount refs;
char *peer_string;
@@ -483,7 +485,8 @@ struct grpc_chttp2_stream {
/** Someone is unlocking the transport mutex: check to see if writes
are required, and schedule them if so */
int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
- grpc_chttp2_transport_writing *writing);
+ grpc_chttp2_transport_writing *writing,
+ int is_parsing);
void grpc_chttp2_perform_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
grpc_endpoint *endpoint);
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index 8cef8fbb77..467e734cc3 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -35,14 +35,15 @@
#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
#include "src/core/profiling/timers.h"
#include "src/core/transport/chttp2/http2_errors.h"
#include "src/core/transport/chttp2/status_conversion.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
+#include "src/core/transport/static_metadata.h"
static int init_frame_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *transport_parsing);
@@ -78,6 +79,9 @@ void grpc_chttp2_prepare_to_read(
GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
transport_parsing->next_stream_id = transport_global->next_stream_id;
+ transport_parsing->last_sent_max_table_size =
+ transport_global->settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
/* update the parsing view of incoming window */
while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
@@ -127,6 +131,7 @@ void grpc_chttp2_publish_reads(
transport_global->settings[GRPC_SENT_SETTINGS],
GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
transport_parsing->settings_ack_received = 0;
+ transport_global->sent_local_settings = 0;
}
/* move goaway to the global state if we received one (it will be
@@ -588,13 +593,12 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
transport_parsing->is_client ? "CLI" : "SVR",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
- if (md->key == transport_parsing->elem_grpc_status_ok->key &&
- md != transport_parsing->elem_grpc_status_ok) {
+ if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
/* TODO(ctiller): check for a status like " 0" */
stream_parsing->seen_error = 1;
}
- if (md->key == transport_parsing->str_grpc_timeout) {
+ if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
if (!cached_timeout) {
/* not already parsed: parse it now, and store the result away */
@@ -635,8 +639,7 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
transport_parsing->is_client ? "CLI" : "SVR",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
- if (md->key == transport_parsing->elem_grpc_status_ok->key &&
- md != transport_parsing->elem_grpc_status_ok) {
+ if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
/* TODO(ctiller): check for a status like " 0" */
stream_parsing->seen_error = 1;
}
@@ -819,6 +822,9 @@ static int init_settings_frame_parser(
}
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
transport_parsing->settings_ack_received = 1;
+ grpc_chttp2_hptbl_set_max_bytes(
+ &transport_parsing->hpack_parser.table,
+ transport_parsing->last_sent_max_table_size);
}
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings;
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 353e476e40..805d05222d 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -45,7 +45,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
int grpc_chttp2_unlocking_check_writes(
grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_transport_writing *transport_writing) {
+ grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
grpc_chttp2_stream_global *stream_global;
grpc_chttp2_stream_writing *stream_writing;
@@ -55,8 +55,13 @@ int grpc_chttp2_unlocking_check_writes(
gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
GPR_ASSERT(transport_global->qbuf.count == 0);
+ grpc_chttp2_hpack_compressor_set_max_table_size(
+ &transport_writing->hpack_compressor,
+ transport_global->settings[GRPC_PEER_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+
if (transport_global->dirtied_local_settings &&
- !transport_global->sent_local_settings) {
+ !transport_global->sent_local_settings && !is_parsing) {
gpr_slice_buffer_add(
&transport_writing->outbuf,
grpc_chttp2_settings_create(
@@ -315,6 +320,8 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
}
}
+
+ GPR_TIMER_END("finalize_outbuf", 0);
}
void grpc_chttp2_cleanup_writing(
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index f62294c7c5..97f2a1b75c 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -49,10 +49,10 @@
#include "src/core/transport/chttp2/internal.h"
#include "src/core/transport/chttp2/status_conversion.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
+#include "src/core/transport/static_metadata.h"
#include "src/core/transport/transport_impl.h"
#define DEFAULT_WINDOW 65535
-#define GRPC_CHTTP2_STREAM_LOOKAHEAD DEFAULT_WINDOW
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
@@ -156,9 +156,6 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
- GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);
- GRPC_MDELEM_UNREF(t->parsing.elem_grpc_status_ok);
-
for (i = 0; i < STREAM_LIST_COUNT; i++) {
GPR_ASSERT(t->lists[i].head == NULL);
GPR_ASSERT(t->lists[i].tail == NULL);
@@ -184,8 +181,6 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
gpr_free(ping);
}
- grpc_mdctx_unref(t->metadata_context);
-
gpr_free(t->peer_string);
gpr_free(t);
}
@@ -220,8 +215,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
const grpc_channel_args *channel_args,
- grpc_endpoint *ep, grpc_mdctx *mdctx,
- gpr_uint8 is_client) {
+ grpc_endpoint *ep, gpr_uint8 is_client) {
size_t i;
int j;
@@ -237,22 +231,17 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* ref is dropped at transport close() */
gpr_ref_init(&t->shutdown_ep_refs, 1);
gpr_mu_init(&t->mu);
- grpc_mdctx_ref(mdctx);
t->peer_string = grpc_endpoint_get_peer(ep);
- t->metadata_context = mdctx;
t->endpoint_reading = 1;
t->global.next_stream_id = is_client ? 1 : 2;
t->global.is_client = is_client;
t->writing.outgoing_window = DEFAULT_WINDOW;
t->parsing.incoming_window = DEFAULT_WINDOW;
+ t->global.stream_lookahead = DEFAULT_WINDOW;
t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
t->global.ping_counter = 1;
t->global.pings.next = t->global.pings.prev = &t->global.pings;
t->parsing.is_client = is_client;
- t->parsing.str_grpc_timeout =
- grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
- t->parsing.elem_grpc_status_ok =
- grpc_mdelem_from_strings(t->metadata_context, "grpc-status", "0");
t->parsing.deframe_state =
is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->writing.is_client = is_client;
@@ -263,12 +252,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_slice_buffer_init(&t->global.qbuf);
gpr_slice_buffer_init(&t->writing.outbuf);
- grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
+ grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
grpc_closure_init(&t->writing_action, writing_action, t);
gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
- grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
+ grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser);
grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
&t->writing);
@@ -338,6 +327,43 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->global.next_stream_id =
(gpr_uint32)channel_args->args[i].value.integer;
}
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
+ if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s: must be an integer",
+ GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
+ } else if (channel_args->args[i].value.integer <= 5) {
+ gpr_log(GPR_ERROR, "%s: must be at least 5",
+ GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
+ } else {
+ t->global.stream_lookahead =
+ (gpr_uint32)channel_args->args[i].value.integer;
+ }
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
+ if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s: must be an integer",
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
+ } else if (channel_args->args[i].value.integer < 0) {
+ gpr_log(GPR_DEBUG, "%s: must be non-negative",
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
+ } else {
+ push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
+ (gpr_uint32)channel_args->args[i].value.integer);
+ }
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
+ if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s: must be an integer",
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
+ } else if (channel_args->args[i].value.integer < 0) {
+ gpr_log(GPR_DEBUG, "%s: must be non-negative",
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
+ } else {
+ grpc_chttp2_hpack_compressor_set_max_usable_size(
+ &t->writing.hpack_compressor,
+ (gpr_uint32)channel_args->args[i].value.integer);
+ }
}
}
}
@@ -563,7 +589,8 @@ static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_TIMER_BEGIN("unlock", 0);
if (!t->writing_active && !t->closed &&
- grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
+ grpc_chttp2_unlocking_check_writes(&t->global, &t->writing,
+ t->parsing_active)) {
t->writing_active = 1;
REF_TRANSPORT(t, "writing");
grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, 1);
@@ -724,17 +751,18 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
static int contains_non_ok_status(
grpc_chttp2_transport_global *transport_global,
grpc_metadata_batch *batch) {
- grpc_mdelem *ok_elem =
- TRANSPORT_FROM_GLOBAL(transport_global)->parsing.elem_grpc_status_ok;
grpc_linked_mdelem *l;
for (l = batch->list.head; l; l = l->next) {
- if (l->md->key == ok_elem->key && l->md != ok_elem) {
+ if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
+ l->md != GRPC_MDELEM_GRPC_STATUS_0) {
return 1;
}
}
return 0;
}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
+
static void perform_stream_op_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
@@ -743,6 +771,9 @@ static void perform_stream_op_locked(
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
on_complete = op->on_complete;
+ if (on_complete == NULL) {
+ on_complete = grpc_closure_create(do_nothing, NULL);
+ }
/* use final_data as a barrier until enqueue time; the inital counter is
dropped at the end of this function */
on_complete->final_data = 2;
@@ -806,7 +837,7 @@ static void perform_stream_op_locked(
}
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
- exec_ctx, &stream_global->send_trailing_metadata_finished,
+ exec_ctx, &stream_global->send_trailing_metadata_finished,
grpc_metadata_batch_is_empty(op->send_trailing_metadata));
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
@@ -1033,20 +1064,20 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
to the upper layers - drop what we've got, and then publish
what we want - which is safe because we haven't told anyone
about the metadata yet */
- if (!stream_global->published_trailing_metadata || stream_global->recv_trailing_metadata_finished != NULL) {
- grpc_mdctx *mdctx =
- TRANSPORT_FROM_GLOBAL(transport_global)->metadata_context;
+ if (!stream_global->published_trailing_metadata ||
+ stream_global->recv_trailing_metadata_finished != NULL) {
char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string);
grpc_chttp2_incoming_metadata_buffer_add(
&stream_global->received_trailing_metadata,
- grpc_mdelem_from_strings(mdctx, "grpc-status", status_string));
+ grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
if (slice) {
grpc_chttp2_incoming_metadata_buffer_add(
&stream_global->received_trailing_metadata,
grpc_mdelem_from_metadata_strings(
- mdctx, grpc_mdstr_from_string(mdctx, "grpc-message"),
- grpc_mdstr_from_slice(mdctx, gpr_slice_ref(*slice))));
+ GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
}
stream_global->published_trailing_metadata = 1;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
@@ -1372,8 +1403,8 @@ static void incoming_byte_stream_update_flow_control(
gpr_uint32 max_recv_bytes;
/* clamp max recv hint to an allowable size */
- if (max_size_hint >= GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD) {
- max_recv_bytes = GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD;
+ if (max_size_hint >= GPR_UINT32_MAX - transport_global->stream_lookahead) {
+ max_recv_bytes = GPR_UINT32_MAX - transport_global->stream_lookahead;
} else {
max_recv_bytes = (gpr_uint32)max_size_hint;
}
@@ -1386,8 +1417,9 @@ static void incoming_byte_stream_update_flow_control(
}
/* add some small lookahead to keep pipelines flowing */
- GPR_ASSERT(max_recv_bytes <= GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD);
- max_recv_bytes += GRPC_CHTTP2_STREAM_LOOKAHEAD;
+ GPR_ASSERT(max_recv_bytes <=
+ GPR_UINT32_MAX - transport_global->stream_lookahead);
+ max_recv_bytes += transport_global->stream_lookahead;
if (stream_global->max_recv_bytes < max_recv_bytes) {
gpr_uint32 add_max_recv_bytes =
max_recv_bytes - stream_global->max_recv_bytes;
@@ -1596,9 +1628,9 @@ static const grpc_transport_vtable vtable = {
grpc_transport *grpc_create_chttp2_transport(
grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
- grpc_endpoint *ep, grpc_mdctx *mdctx, int is_client) {
+ grpc_endpoint *ep, int is_client) {
grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
- init_transport(exec_ctx, t, channel_args, ep, mdctx, is_client != 0);
+ init_transport(exec_ctx, t, channel_args, ep, is_client != 0);
return &t->base;
}
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
index fce2b680fd..95520501ed 100644
--- a/src/core/transport/chttp2_transport.h
+++ b/src/core/transport/chttp2_transport.h
@@ -42,7 +42,7 @@ extern int grpc_flowctl_trace;
grpc_transport *grpc_create_chttp2_transport(
grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
- grpc_endpoint *ep, grpc_mdctx *metadata_context, int is_client);
+ grpc_endpoint *ep, int is_client);
void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index a72dee4399..56e83a0a75 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -31,20 +31,32 @@
*
*/
-#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/metadata.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>
+#include <grpc/compression.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/profiling/timers.h"
#include "src/core/support/murmur_hash.h"
+#include "src/core/support/string.h"
#include "src/core/transport/chttp2/bin_encoder.h"
+#include "src/core/transport/static_metadata.h"
+
+/* 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().
+ * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
+ * by internal_string and internal_element structures.
+ * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
+ * used to determine which kind of element a pointer refers to.
+ */
#define INITIAL_STRTAB_CAPACITY 4
#define INITIAL_MDTAB_CAPACITY 4
@@ -52,107 +64,188 @@
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
#define DEBUG_ARGS , const char *file, int line
#define FWD_DEBUG_ARGS , file, line
-#define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
-#define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
-#define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
+#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
#else
#define DEBUG_ARGS
#define FWD_DEBUG_ARGS
-#define INTERNAL_STRING_REF(s) internal_string_ref((s))
-#define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
-#define REF_MD_LOCKED(s) ref_md_locked((s))
+#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);
+/* Shadow structure for grpc_mdstr for non-static values */
typedef struct internal_string {
/* must be byte compatible with grpc_mdstr */
gpr_slice slice;
gpr_uint32 hash;
/* private only data */
- gpr_uint32 refs;
+ gpr_atm refcnt;
+
gpr_uint8 has_base64_and_huffman_encoded;
gpr_slice_refcount refcount;
gpr_slice base64_and_huffman;
- grpc_mdctx *context;
-
struct internal_string *bucket_next;
} internal_string;
+/* 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;
+ /* private only data */
gpr_atm refcnt;
- /* private only data */
gpr_mu mu_user_data;
gpr_atm destroy_user_data;
gpr_atm user_data;
- grpc_mdctx *context;
struct internal_metadata *bucket_next;
} internal_metadata;
-struct grpc_mdctx {
- gpr_uint32 hash_seed;
- int refs;
-
+typedef struct strtab_shard {
gpr_mu mu;
+ internal_string **strs;
+ size_t count;
+ size_t capacity;
+} strtab_shard;
- internal_string **strtab;
- size_t strtab_count;
- size_t strtab_capacity;
+typedef struct mdtab_shard {
+ gpr_mu mu;
+ internal_metadata **elems;
+ size_t count;
+ size_t capacity;
+ size_t free;
+} 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 gpr_uint32 g_hash_seed;
+
+/* 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 void gc_mdtab(mdtab_shard *shard);
+
+void grpc_mdctx_global_init(void) {
+ size_t i, j;
+ g_hash_seed = (gpr_uint32)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];
+ gpr_uint32 hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
+ *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
+ *(gpr_uint32 *)&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]];
+ gpr_uint32 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];
+ gpr_mu_init(&shard->mu);
+ shard->count = 0;
+ shard->free = 0;
+ shard->capacity = INITIAL_MDTAB_CAPACITY;
+ shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
+ memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
+ }
+}
- internal_metadata **mdtab;
- size_t mdtab_count;
- size_t mdtab_free;
- size_t mdtab_capacity;
-};
-
-static void internal_string_ref(internal_string *s DEBUG_ARGS);
-static void internal_string_unref(internal_string *s DEBUG_ARGS);
-static void discard_metadata(grpc_mdctx *ctx);
-static void gc_mdtab(grpc_mdctx *ctx);
-static void metadata_context_destroy_locked(grpc_mdctx *ctx);
-
-static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
-
-static void unlock(grpc_mdctx *ctx) {
- /* If the context has been orphaned we'd like to delete it soon. We check
- conditions in unlock as it signals the end of mutations on a context.
-
- We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted
- first. This is equivalent to saying that both tables have zero counts,
- which is equivalent to saying that strtab_count is zero (as mdelem's MUST
- reference an mdstr for their key and value slots).
-
- To encourage that to happen, we start discarding zero reference count
- mdelems on every unlock (instead of the usual 'I'm too loaded' trigger
- case), since otherwise we can be stuck waiting for a garbage collection
- that will never happen. */
- if (ctx->refs == 0) {
-/* uncomment if you're having trouble diagnosing an mdelem leak to make
- things clearer (slows down destruction a lot, however) */
-#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gc_mdtab(ctx);
-#endif
- if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
- discard_metadata(ctx);
+void grpc_mdctx_global_shutdown(void) {
+ size_t i;
+ for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
+ mdtab_shard *shard = &g_mdtab_shard[i];
+ gpr_mu_destroy(&shard->mu);
+ gc_mdtab(shard);
+ /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
+ if (shard->count != 0) {
+ gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
+ shard->count);
}
- if (ctx->strtab_count == 0) {
- metadata_context_destroy_locked(ctx);
- return;
+ 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: %d metadata strings were leaked",
+ shard->count);
}
+ gpr_free(shard->strs);
}
- gpr_mu_unlock(&ctx->mu);
}
-static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
+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 void ref_md_locked(mdtab_shard *shard,
+ internal_metadata *md DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%d->%d: '%s' = '%s'", md,
@@ -162,96 +255,14 @@ static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
- md->context->mdtab_free--;
+ shard->free--;
} else {
GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
}
}
-grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
- grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
-
- ctx->refs = 1;
- ctx->hash_seed = seed;
- gpr_mu_init(&ctx->mu);
- ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
- memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);
- ctx->strtab_count = 0;
- ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY;
- ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY);
- memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY);
- ctx->mdtab_count = 0;
- ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
- ctx->mdtab_free = 0;
-
- return ctx;
-}
-
-grpc_mdctx *grpc_mdctx_create(void) {
- /* This seed is used to prevent remote connections from controlling hash table
- * collisions. It needs to be somewhat unpredictable to a remote connection.
- */
- return grpc_mdctx_create_with_seed(
- (gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
-}
-
-static void discard_metadata(grpc_mdctx *ctx) {
- size_t i;
- internal_metadata *next, *cur;
-
- for (i = 0; i < ctx->mdtab_capacity; i++) {
- cur = ctx->mdtab[i];
- while (cur) {
- void *user_data = (void *)gpr_atm_no_barrier_load(&cur->user_data);
- GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
- next = cur->bucket_next;
- INTERNAL_STRING_UNREF(cur->key);
- INTERNAL_STRING_UNREF(cur->value);
- if (user_data != NULL) {
- ((destroy_user_data_func)gpr_atm_no_barrier_load(
- &cur->destroy_user_data))(user_data);
- }
- gpr_mu_destroy(&cur->mu_user_data);
- gpr_free(cur);
- cur = next;
- ctx->mdtab_free--;
- ctx->mdtab_count--;
- }
- ctx->mdtab[i] = NULL;
- }
-}
-
-static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
- GPR_ASSERT(ctx->strtab_count == 0);
- GPR_ASSERT(ctx->mdtab_count == 0);
- GPR_ASSERT(ctx->mdtab_free == 0);
- gpr_free(ctx->strtab);
- gpr_free(ctx->mdtab);
- gpr_mu_unlock(&ctx->mu);
- gpr_mu_destroy(&ctx->mu);
- gpr_free(ctx);
-}
-
-void grpc_mdctx_ref(grpc_mdctx *ctx) {
- GPR_TIMER_BEGIN("grpc_mdctx_ref", 0);
- lock(ctx);
- GPR_ASSERT(ctx->refs > 0);
- ctx->refs++;
- unlock(ctx);
- GPR_TIMER_END("grpc_mdctx_ref", 0);
-}
-
-void grpc_mdctx_unref(grpc_mdctx *ctx) {
- GPR_TIMER_BEGIN("grpc_mdctx_unref", 0);
- lock(ctx);
- GPR_ASSERT(ctx->refs > 0);
- ctx->refs--;
- unlock(ctx);
- GPR_TIMER_END("grpc_mdctx_unref", 0);
-}
-
-static void grow_strtab(grpc_mdctx *ctx) {
- size_t capacity = ctx->strtab_capacity * 2;
+static void grow_strtab(strtab_shard *shard) {
+ size_t capacity = shard->capacity * 2;
size_t i;
internal_string **strtab;
internal_string *s, *next;
@@ -261,105 +272,95 @@ static void grow_strtab(grpc_mdctx *ctx) {
strtab = gpr_malloc(sizeof(internal_string *) * capacity);
memset(strtab, 0, sizeof(internal_string *) * capacity);
- for (i = 0; i < ctx->strtab_capacity; i++) {
- for (s = ctx->strtab[i]; s; s = next) {
+ 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[s->hash % capacity];
- strtab[s->hash % capacity] = s;
+ s->bucket_next = strtab[idx];
+ strtab[idx] = s;
}
}
- gpr_free(ctx->strtab);
- ctx->strtab = strtab;
- ctx->strtab_capacity = capacity;
+ gpr_free(shard->strs);
+ shard->strs = strtab;
+ shard->capacity = capacity;
GPR_TIMER_END("grow_strtab", 0);
}
-static void internal_destroy_string(internal_string *is) {
+static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
internal_string **prev_next;
internal_string *cur;
- grpc_mdctx *ctx = is->context;
GPR_TIMER_BEGIN("internal_destroy_string", 0);
if (is->has_base64_and_huffman_encoded) {
gpr_slice_unref(is->base64_and_huffman);
}
- for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity],
+ 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;
- ctx->strtab_count--;
+ shard->count--;
gpr_free(is);
GPR_TIMER_END("internal_destroy_string", 0);
}
-static void internal_string_ref(internal_string *s DEBUG_ARGS) {
-#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%d->%d: '%s'", s,
- s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
-#endif
- ++s->refs;
-}
-
-static void internal_string_unref(internal_string *s DEBUG_ARGS) {
-#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s,
- s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
-#endif
- GPR_ASSERT(s->refs > 0);
- if (0 == --s->refs) {
- internal_destroy_string(s);
- }
-}
-
static void slice_ref(void *p) {
internal_string *is =
(internal_string *)((char *)p - offsetof(internal_string, refcount));
- grpc_mdctx *ctx = is->context;
- GPR_TIMER_BEGIN("slice_ref", 0);
- lock(ctx);
- INTERNAL_STRING_REF(is);
- unlock(ctx);
- GPR_TIMER_END("slice_ref", 0);
+ GRPC_MDSTR_REF((grpc_mdstr *)(is));
}
static void slice_unref(void *p) {
internal_string *is =
(internal_string *)((char *)p - offsetof(internal_string, refcount));
- grpc_mdctx *ctx = is->context;
- GPR_TIMER_BEGIN("slice_unref", 0);
- lock(ctx);
- INTERNAL_STRING_UNREF(is);
- unlock(ctx);
- GPR_TIMER_END("slice_unref", 0);
+ GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
}
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
- return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
+grpc_mdstr *grpc_mdstr_from_string(const char *str) {
+ return grpc_mdstr_from_buffer((const gpr_uint8 *)str, strlen(str));
}
-grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) {
- grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice),
+grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
+ grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
GPR_SLICE_LENGTH(slice));
gpr_slice_unref(slice);
return result;
}
-grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
- size_t length) {
- gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
+grpc_mdstr *grpc_mdstr_from_buffer(const gpr_uint8 *buf, size_t length) {
+ gpr_uint32 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);
- lock(ctx);
+
+ /* 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 && GPR_SLICE_LENGTH(ss->slice) == length &&
+ 0 == memcmp(buf, GPR_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 */
- for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
+ idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
+ for (s = shard->strs[idx]; s; s = s->bucket_next) {
if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
- INTERNAL_STRING_REF(s);
- unlock(ctx);
+ GRPC_MDSTR_REF((grpc_mdstr *)s);
+ gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return (grpc_mdstr *)s;
}
@@ -369,7 +370,7 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
if (length + 1 < GPR_SLICE_INLINED_SIZE) {
/* string data goes directly into the slice */
s = gpr_malloc(sizeof(internal_string));
- s->refs = 1;
+ gpr_atm_rel_store(&s->refcnt, 2);
s->slice.refcount = NULL;
memcpy(s->slice.data.inlined.bytes, buf, length);
s->slice.data.inlined.bytes[length] = 0;
@@ -378,7 +379,7 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
/* string data goes after the internal_string header, and we +1 for null
terminator */
s = gpr_malloc(sizeof(internal_string) + length + 1);
- s->refs = 1;
+ gpr_atm_rel_store(&s->refcnt, 2);
s->refcount.ref = slice_ref;
s->refcount.unref = slice_unref;
s->slice.refcount = &s->refcount;
@@ -390,44 +391,43 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
}
s->has_base64_and_huffman_encoded = 0;
s->hash = hash;
- s->context = ctx;
- s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity];
- ctx->strtab[hash % ctx->strtab_capacity] = s;
+ s->bucket_next = shard->strs[idx];
+ shard->strs[idx] = s;
- ctx->strtab_count++;
+ shard->count++;
- if (ctx->strtab_count > ctx->strtab_capacity * 2) {
- grow_strtab(ctx);
+ if (shard->count > shard->capacity * 2) {
+ grow_strtab(shard);
}
- unlock(ctx);
+ gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return (grpc_mdstr *)s;
}
-static void gc_mdtab(grpc_mdctx *ctx) {
+static void gc_mdtab(mdtab_shard *shard) {
size_t i;
internal_metadata **prev_next;
internal_metadata *md, *next;
GPR_TIMER_BEGIN("gc_mdtab", 0);
- for (i = 0; i < ctx->mdtab_capacity; i++) {
- prev_next = &ctx->mdtab[i];
- for (md = ctx->mdtab[i]; md; md = next) {
+ for (i = 0; i < shard->capacity; i++) {
+ prev_next = &shard->elems[i];
+ for (md = shard->elems[i]; md; md = next) {
void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
next = md->bucket_next;
if (gpr_atm_acq_load(&md->refcnt) == 0) {
- INTERNAL_STRING_UNREF(md->key);
- INTERNAL_STRING_UNREF(md->value);
+ GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
+ GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
if (md->user_data) {
((destroy_user_data_func)gpr_atm_no_barrier_load(
&md->destroy_user_data))(user_data);
}
gpr_free(md);
*prev_next = next;
- ctx->mdtab_free--;
- ctx->mdtab_count--;
+ shard->free--;
+ shard->count--;
} else {
prev_next = &md->bucket_next;
}
@@ -436,8 +436,8 @@ static void gc_mdtab(grpc_mdctx *ctx) {
GPR_TIMER_END("gc_mdtab", 0);
}
-static void grow_mdtab(grpc_mdctx *ctx) {
- size_t capacity = ctx->mdtab_capacity * 2;
+static void grow_mdtab(mdtab_shard *shard) {
+ size_t capacity = shard->capacity * 2;
size_t i;
internal_metadata **mdtab;
internal_metadata *md, *next;
@@ -448,52 +448,67 @@ static void grow_mdtab(grpc_mdctx *ctx) {
mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
- for (i = 0; i < ctx->mdtab_capacity; i++) {
- for (md = ctx->mdtab[i]; md; md = next) {
+ 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);
next = md->bucket_next;
- md->bucket_next = mdtab[hash % capacity];
- mdtab[hash % capacity] = md;
+ idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
+ md->bucket_next = mdtab[idx];
+ mdtab[idx] = md;
}
}
- gpr_free(ctx->mdtab);
- ctx->mdtab = mdtab;
- ctx->mdtab_capacity = capacity;
+ gpr_free(shard->elems);
+ shard->elems = mdtab;
+ shard->capacity = capacity;
GPR_TIMER_END("grow_mdtab", 0);
}
-static void rehash_mdtab(grpc_mdctx *ctx) {
- if (ctx->mdtab_free > ctx->mdtab_capacity / 4) {
- gc_mdtab(ctx);
+static void rehash_mdtab(mdtab_shard *shard) {
+ if (shard->free > shard->capacity / 4) {
+ gc_mdtab(shard);
} else {
- grow_mdtab(ctx);
+ grow_mdtab(shard);
}
}
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
- grpc_mdstr *mkey,
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
grpc_mdstr *mvalue) {
internal_string *key = (internal_string *)mkey;
internal_string *value = (internal_string *)mvalue;
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
internal_metadata *md;
-
- GPR_ASSERT(key->context == ctx);
- GPR_ASSERT(value->context == ctx);
+ mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
+ size_t i;
+ size_t idx;
GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
- lock(ctx);
+ 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;
+ }
+ }
+ }
+
+ gpr_mu_lock(&shard->mu);
+ idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
/* search for an existing pair */
- for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
+ for (md = shard->elems[idx]; md; md = md->bucket_next) {
if (md->key == key && md->value == value) {
- REF_MD_LOCKED(md);
- INTERNAL_STRING_UNREF(key);
- INTERNAL_STRING_UNREF(value);
- unlock(ctx);
+ REF_MD_LOCKED(shard, md);
+ GRPC_MDSTR_UNREF((grpc_mdstr *)key);
+ GRPC_MDSTR_UNREF((grpc_mdstr *)value);
+ gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
return (grpc_mdelem *)md;
}
@@ -502,12 +517,12 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
/* not found: create a new pair */
md = gpr_malloc(sizeof(internal_metadata));
gpr_atm_rel_store(&md->refcnt, 2);
- md->context = ctx;
md->key = key;
md->value = value;
md->user_data = 0;
md->destroy_user_data = 0;
- md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
+ md->bucket_next = shard->elems[idx];
+ shard->elems[idx] = md;
gpr_mu_init(&md->mu_user_data);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
@@ -515,44 +530,39 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
- ctx->mdtab[hash % ctx->mdtab_capacity] = md;
- ctx->mdtab_count++;
+ shard->count++;
- if (ctx->mdtab_count > ctx->mdtab_capacity * 2) {
- rehash_mdtab(ctx);
+ if (shard->count > shard->capacity * 2) {
+ rehash_mdtab(shard);
}
- unlock(ctx);
+ gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
return (grpc_mdelem *)md;
}
-grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
- const char *value) {
- return grpc_mdelem_from_metadata_strings(ctx,
- grpc_mdstr_from_string(ctx, key),
- grpc_mdstr_from_string(ctx, value));
+grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
+ return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
+ grpc_mdstr_from_string(value));
}
-grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
- gpr_slice value) {
- return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key),
- grpc_mdstr_from_slice(ctx, value));
+grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
+ return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
+ grpc_mdstr_from_slice(value));
}
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
- const char *key,
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
const gpr_uint8 *value,
size_t value_length) {
return grpc_mdelem_from_metadata_strings(
- ctx, grpc_mdstr_from_string(ctx, key),
- grpc_mdstr_from_buffer(ctx, value, value_length));
+ grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
}
grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
+ if (is_mdelem_static(gmd)) return gmd;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%d->%d: '%s' = '%s'", md,
@@ -573,6 +583,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (!md) return;
+ if (is_mdelem_static(gmd)) return;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
@@ -582,14 +593,16 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
- grpc_mdctx *ctx = md->context;
+ gpr_uint32 hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+ mdtab_shard *shard =
+ &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
- lock(ctx);
+ gpr_mu_lock(&shard->mu);
if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
- ctx->mdtab_free++;
+ shard->free++;
gpr_atm_no_barrier_store(&md->refcnt, 0);
}
- unlock(ctx);
+ gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
}
}
@@ -600,36 +613,31 @@ const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
- grpc_mdctx *ctx = s->context;
- lock(ctx);
- internal_string_ref(s FWD_DEBUG_ARGS);
- unlock(ctx);
+ if (is_mdstr_static(gs)) return gs;
+ GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
return gs;
}
void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
- grpc_mdctx *ctx = s->context;
- lock(ctx);
- internal_string_unref(s FWD_DEBUG_ARGS);
- unlock(ctx);
-}
-
-size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) {
- return ctx->mdtab_capacity;
-}
-
-size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) {
- return ctx->mdtab_count;
-}
-
-size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
- return ctx->mdtab_free;
+ if (is_mdstr_static(gs)) return;
+ if (2 == 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);
+ if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
+ internal_destroy_string(shard, s);
+ }
+ gpr_mu_unlock(&shard->mu);
+ }
}
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 {
@@ -641,6 +649,7 @@ void *grpc_mdelem_get_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)) {
@@ -659,15 +668,16 @@ void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
internal_string *s = (internal_string *)gs;
gpr_slice slice;
- grpc_mdctx *ctx = s->context;
- lock(ctx);
+ 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;
- unlock(ctx);
+ gpr_mu_unlock(&shard->mu);
return slice;
}
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 9a8164037c..c1071e4e16 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -59,10 +59,15 @@
grpc_mdelem instances MAY live longer than their refcount implies, and are
garbage collected periodically, meaning cached data can easily outlive a
- single request. */
+ single request.
+
+ STATIC METADATA: in static_metadata.h we declare a set of static metadata.
+ These mdelems and mdstrs are available via pre-declared code generated macros
+ and are available to code anywhere between grpc_init() and grpc_shutdown().
+ They are not refcounted, but can be passed to _ref and _unref functions
+ declared here - in which case those functions are effectively no-ops. */
/* Forward declarations */
-typedef struct grpc_mdctx grpc_mdctx;
typedef struct grpc_mdstr grpc_mdstr;
typedef struct grpc_mdelem grpc_mdelem;
@@ -81,25 +86,18 @@ struct grpc_mdelem {
/* there is a private part to this in metadata.c */
};
-/* Create/orphan a metadata context */
-grpc_mdctx *grpc_mdctx_create(void);
-grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed);
-void grpc_mdctx_ref(grpc_mdctx *mdctx);
-void grpc_mdctx_unref(grpc_mdctx *mdctx);
-
/* Test only accessors to internal state - only for testing this code - do not
rely on it outside of metadata_test.c */
-size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *mdctx);
-size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *mdctx);
-size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
+size_t grpc_mdctx_get_mdtab_capacity_test_only(void);
+size_t grpc_mdctx_get_mdtab_count_test_only(void);
+size_t grpc_mdctx_get_mdtab_free_test_only(void);
/* Constructors for grpc_mdstr instances; take a variety of data types that
clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str);
+grpc_mdstr *grpc_mdstr_from_string(const char *str);
/* Unrefs the slice. */
-grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
-grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
- size_t length);
+grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice);
+grpc_mdstr *grpc_mdstr_from_buffer(const gpr_uint8 *str, size_t length);
/* Returns a borrowed slice from the mdstr with its contents base64 encoded
and huffman compressed */
@@ -107,15 +105,12 @@ gpr_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_mdctx *ctx, grpc_mdstr *key,
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
grpc_mdstr *value);
-grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
- const char *value);
+grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
/* Unrefs the slices. */
-grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
- gpr_slice value);
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
- const char *key,
+grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value);
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
const gpr_uint8 *value,
size_t value_length);
@@ -157,4 +152,7 @@ int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);
#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(void);
+
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
new file mode 100644
index 0000000000..e7aff325c2
--- /dev/null
+++ b/src/core/transport/static_metadata.c
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py,
+ * and then re-run it.
+ *
+ * See metadata.h for an explanation of the interface here, and metadata.c for
+ * an
+ * explanation of what's going on.
+ */
+
+#include "src/core/transport/static_metadata.h"
+
+grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+
+grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+gpr_uintptr 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, 3, 7, 5, 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};
+
+const gpr_uint8
+ grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = {
+ 11, 33, 10, 33, 12, 33, 12, 47, 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, 46, 40, 51, 40, 52, 40, 53, 40, 54, 41, 31, 41, 46, 41, 51,
+ 44, 0, 44, 1, 44, 2, 48, 33, 55, 33, 56, 33, 57, 33, 58, 33, 59, 33,
+ 60, 33, 61, 33, 62, 33, 63, 33, 64, 38, 64, 66, 65, 76, 65, 77, 67, 33,
+ 68, 33, 69, 33, 70, 33, 71, 33, 72, 33, 73, 39, 73, 49, 73, 50, 74, 33,
+ 75, 33, 78, 3, 78, 4, 78, 5, 78, 6, 78, 7, 78, 8, 78, 9, 79, 33,
+ 80, 81, 82, 33, 83, 33, 84, 33, 85, 33, 86, 33};
+
+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-status",
+ "grpc-timeout",
+ "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",
+ "link",
+ "location",
+ "max-forwards",
+ ":method",
+ ":path",
+ "POST",
+ "proxy-authenticate",
+ "proxy-authorization",
+ "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"};
+
+const gpr_uint8 grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30,
+ 28, 32, 27, 31};
diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h
new file mode 100644
index 0000000000..e9055fb45c
--- /dev/null
+++ b/src/core/transport/static_metadata.h
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py,
+ * and then re-run it.
+ *
+ * See metadata.h for an explanation of the interface here, and metadata.c for
+ * an
+ * explanation of what's going on.
+ */
+
+#ifndef GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
+#define GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
+
+#include "src/core/transport/metadata.h"
+
+#define GRPC_STATIC_MDSTR_COUNT 87
+extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+/* "0" */
+#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
+/* "1" */
+#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1])
+/* "2" */
+#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2])
+/* "200" */
+#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3])
+/* "204" */
+#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4])
+/* "206" */
+#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5])
+/* "304" */
+#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6])
+/* "400" */
+#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7])
+/* "404" */
+#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8])
+/* "500" */
+#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9])
+/* "accept" */
+#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10])
+/* "accept-charset" */
+#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11])
+/* "accept-encoding" */
+#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12])
+/* "accept-language" */
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13])
+/* "accept-ranges" */
+#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14])
+/* "access-control-allow-origin" */
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15])
+/* "age" */
+#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16])
+/* "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])
+/* "authorization" */
+#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
+/* "cache-control" */
+#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
+/* "content-disposition" */
+#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22])
+/* "content-encoding" */
+#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23])
+/* "content-language" */
+#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24])
+/* "content-length" */
+#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25])
+/* "content-location" */
+#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26])
+/* "content-range" */
+#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27])
+/* "content-type" */
+#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28])
+/* "cookie" */
+#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29])
+/* "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])
+/* "etag" */
+#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34])
+/* "expect" */
+#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35])
+/* "expires" */
+#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36])
+/* "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-status" */
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[44])
+/* "grpc-timeout" */
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[45])
+/* "gzip" */
+#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[46])
+/* "gzip, deflate" */
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[47])
+/* "host" */
+#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[48])
+/* "http" */
+#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[49])
+/* "https" */
+#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[50])
+/* "identity" */
+#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[51])
+/* "identity,deflate" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[52])
+/* "identity,deflate,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
+ (&grpc_static_mdstr_table[53])
+/* "identity,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[54])
+/* "if-match" */
+#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[55])
+/* "if-modified-since" */
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[56])
+/* "if-none-match" */
+#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[57])
+/* "if-range" */
+#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[58])
+/* "if-unmodified-since" */
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[59])
+/* "last-modified" */
+#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[60])
+/* "link" */
+#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[61])
+/* "location" */
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[62])
+/* "max-forwards" */
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[63])
+/* ":method" */
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[64])
+/* ":path" */
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[65])
+/* "POST" */
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[66])
+/* "proxy-authenticate" */
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[67])
+/* "proxy-authorization" */
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[68])
+/* "range" */
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[69])
+/* "referer" */
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[70])
+/* "refresh" */
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[71])
+/* "retry-after" */
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[72])
+/* ":scheme" */
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[73])
+/* "server" */
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[74])
+/* "set-cookie" */
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[75])
+/* "/" */
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[76])
+/* "/index.html" */
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[77])
+/* ":status" */
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[78])
+/* "strict-transport-security" */
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[79])
+/* "te" */
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[80])
+/* "trailers" */
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[81])
+/* "transfer-encoding" */
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[82])
+/* "user-agent" */
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[83])
+/* "vary" */
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[84])
+/* "via" */
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[85])
+/* "www-authenticate" */
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[86])
+
+#define GRPC_STATIC_MDELEM_COUNT 78
+extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+extern gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
+/* "accept-charset": "" */
+#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0])
+/* "accept": "" */
+#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1])
+/* "accept-encoding": "" */
+#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2])
+/* "accept-encoding": "gzip, deflate" */
+#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
+ (&grpc_static_mdelem_table[3])
+/* "accept-language": "" */
+#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4])
+/* "accept-ranges": "" */
+#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5])
+/* "access-control-allow-origin": "" */
+#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
+ (&grpc_static_mdelem_table[6])
+/* "age": "" */
+#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7])
+/* "allow": "" */
+#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8])
+/* ":authority": "" */
+#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9])
+/* "authorization": "" */
+#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10])
+/* "cache-control": "" */
+#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11])
+/* "content-disposition": "" */
+#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12])
+/* "content-encoding": "" */
+#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13])
+/* "content-language": "" */
+#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14])
+/* "content-length": "" */
+#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15])
+/* "content-location": "" */
+#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16])
+/* "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])
+/* "content-type": "" */
+#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19])
+/* "cookie": "" */
+#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20])
+/* "date": "" */
+#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21])
+/* "etag": "" */
+#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22])
+/* "expect": "" */
+#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23])
+/* "expires": "" */
+#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24])
+/* "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])
+/* "host": "" */
+#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39])
+/* "if-match": "" */
+#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40])
+/* "if-modified-since": "" */
+#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41])
+/* "if-none-match": "" */
+#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42])
+/* "if-range": "" */
+#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43])
+/* "if-unmodified-since": "" */
+#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44])
+/* "last-modified": "" */
+#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
+/* "link": "" */
+#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46])
+/* "location": "" */
+#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47])
+/* "max-forwards": "" */
+#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48])
+/* ":method": "GET" */
+#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49])
+/* ":method": "POST" */
+#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50])
+/* ":path": "/" */
+#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51])
+/* ":path": "/index.html" */
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52])
+/* "proxy-authenticate": "" */
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53])
+/* "proxy-authorization": "" */
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54])
+/* "range": "" */
+#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55])
+/* "referer": "" */
+#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56])
+/* "refresh": "" */
+#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57])
+/* "retry-after": "" */
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58])
+/* ":scheme": "grpc" */
+#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59])
+/* ":scheme": "http" */
+#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60])
+/* ":scheme": "https" */
+#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61])
+/* "server": "" */
+#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62])
+/* "set-cookie": "" */
+#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63])
+/* ":status": "200" */
+#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64])
+/* ":status": "204" */
+#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65])
+/* ":status": "206" */
+#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66])
+/* ":status": "304" */
+#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67])
+/* ":status": "400" */
+#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68])
+/* ":status": "404" */
+#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69])
+/* ":status": "500" */
+#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70])
+/* "strict-transport-security": "" */
+#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
+ (&grpc_static_mdelem_table[71])
+/* "te": "trailers" */
+#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72])
+/* "transfer-encoding": "" */
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73])
+/* "user-agent": "" */
+#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74])
+/* "vary": "" */
+#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75])
+/* "via": "" */
+#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76])
+/* "www-authenticate": "" */
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77])
+
+extern const gpr_uint8
+ grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
+extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT];
+extern const gpr_uint8 grpc_static_accept_encoding_metadata[8];
+#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
+ (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]])
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 563fa9267d..1293203b93 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -54,7 +54,9 @@ class InsecureChannelCredentialsImpl GRPC_FINAL : public ChannelCredentials {
grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr));
}
- SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
+ SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE {
+ return nullptr;
+ }
};
} // namespace
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index a1b9a3018e..96ae25b761 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,12 +31,13 @@
*
*/
-#include <grpc/support/log.h>
#include <grpc++/channel.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>
+#include <grpc/support/log.h>
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/client/secure_credentials.h"
+#include "src/cpp/common/secure_auth_context.h"
namespace grpc {
@@ -160,7 +161,7 @@ void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
}
void MetadataCredentialsPluginWrapper::GetMetadata(
- void* wrapper, const char* service_url,
+ void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data) {
GPR_ASSERT(wrapper);
MetadataCredentialsPluginWrapper* w =
@@ -171,18 +172,25 @@ void MetadataCredentialsPluginWrapper::GetMetadata(
}
if (w->plugin_->IsBlocking()) {
w->thread_pool_->Add(
- std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w,
- service_url, cb, user_data));
+ std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context,
+ cb, user_data));
} else {
- w->InvokePlugin(service_url, cb, user_data);
+ w->InvokePlugin(context, cb, user_data);
}
}
void MetadataCredentialsPluginWrapper::InvokePlugin(
- const char* service_url, grpc_credentials_plugin_metadata_cb cb,
+ grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
void* user_data) {
std::multimap<grpc::string, grpc::string> metadata;
- Status status = plugin_->GetMetadata(service_url, &metadata);
+
+ // const_cast is safe since the SecureAuthContext does not take owndership and
+ // the object is passed as a const ref to plugin_->GetMetadata.
+ SecureAuthContext cpp_channel_auth_context(
+ const_cast<grpc_auth_context*>(context.channel_auth_context), false);
+
+ Status status = plugin_->GetMetadata(context.service_url, context.method_name,
+ cpp_channel_auth_context, &metadata);
std::vector<grpc_metadata> md;
for (auto it = metadata.begin(); it != metadata.end(); ++it) {
grpc_metadata md_entry;
@@ -204,11 +212,12 @@ MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
GrpcLibrary init; // To call grpc_init().
+ const char* type = plugin->GetType();
MetadataCredentialsPluginWrapper* wrapper =
new MetadataCredentialsPluginWrapper(std::move(plugin));
grpc_metadata_credentials_plugin c_plugin = {
MetadataCredentialsPluginWrapper::GetMetadata,
- MetadataCredentialsPluginWrapper::Destroy, wrapper};
+ MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
return WrapCallCredentials(
grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
}
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index b241761a7c..cef59292dd 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -76,11 +76,10 @@ class SecureCallCredentials GRPC_FINAL : public CallCredentials {
grpc_call_credentials* const c_creds_;
};
-
class MetadataCredentialsPluginWrapper GRPC_FINAL {
public:
static void Destroy(void* wrapper);
- static void GetMetadata(void* wrapper, const char* service_url,
+ static void GetMetadata(void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void* user_data);
@@ -88,7 +87,7 @@ class MetadataCredentialsPluginWrapper GRPC_FINAL {
std::unique_ptr<MetadataCredentialsPlugin> plugin);
private:
- void InvokePlugin(const char* service_url,
+ void InvokePlugin(grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data);
std::unique_ptr<ThreadPoolInterface> thread_pool_;
std::unique_ptr<MetadataCredentialsPlugin> plugin_;
diff --git a/src/csharp/Grpc.Core/Profiling/IProfiler.cs b/src/csharp/Grpc.Core/Profiling/IProfiler.cs
index c426c365d2..e850375004 100644
--- a/src/csharp/Grpc.Core/Profiling/IProfiler.cs
+++ b/src/csharp/Grpc.Core/Profiling/IProfiler.cs
@@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling
internal interface IProfiler
{
void Begin(string tag);
+
void End(string tag);
+
void Mark(string tag);
}
}
diff --git a/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs
index 5cc4c3c054..792e3c3cd0 100644
--- a/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs
+++ b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs
@@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling
{
internal struct ProfilerEntry
{
- public enum Type {
+ public enum Type
+ {
BEGIN,
END,
MARK
diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs
index c8123347f2..471ee20875 100644
--- a/src/csharp/Grpc.Core/Profiling/Profilers.cs
+++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs
@@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling
{
internal static class Profilers
{
- static readonly NopProfiler defaultProfiler = new NopProfiler();
+ static readonly NopProfiler DefaultProfiler = new NopProfiler();
static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>();
public static IProfiler ForCurrentThread()
{
- return profilers.Value ?? defaultProfiler;
+ return profilers.Value ?? DefaultProfiler;
}
public static void SetForCurrentThread(IProfiler profiler)
@@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling
this.entries = new ProfilerEntry[capacity];
}
- public void Begin(string tag) {
+ public void Begin(string tag)
+ {
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag));
}
- public void End(string tag) {
+ public void End(string tag)
+ {
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag));
}
- public void Mark(string tag) {
+ public void Mark(string tag)
+ {
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag));
}
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index e9ec30e923..818ddb83b9 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -41,6 +41,6 @@ namespace Grpc.Core
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "0.7.1";
+ public const string CurrentVersion = "0.12.0";
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore b/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore
new file mode 100644
index 0000000000..a382af2294
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore
@@ -0,0 +1,3 @@
+bin
+obj
+
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
new file mode 100644
index 0000000000..8b245ade2e
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
+ <AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Grpc.Core\Version.cs">
+ <Link>Version.cs</Link>
+ </Compile>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
+ <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
+ <Name>Grpc.IntegrationTesting</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs
new file mode 100644
index 0000000000..308463337f
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs
@@ -0,0 +1,46 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using Grpc.IntegrationTesting;
+
+namespace Grpc.IntegrationTesting
+{
+ class Program
+ {
+ public static void Main(string[] args)
+ {
+ QpsWorker.Run(args);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..aacfc16ef4
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.IntegrationTesting.QpsWorker")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
new file mode 100644
index 0000000000..47a15224f1
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
@@ -0,0 +1,76 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Testing
+{
+ /// <summary>
+ /// Implementation of BenchmarkService server
+ /// </summary>
+ public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
+ {
+ private readonly int responseSize;
+
+ public BenchmarkServiceImpl(int responseSize)
+ {
+ this.responseSize = responseSize;
+ }
+
+ public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+ {
+ var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+ return Task.FromResult(response);
+ }
+
+ public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
+ {
+ await requestStream.ForEachAsync(async request =>
+ {
+ var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+ await responseStream.WriteAsync(response);
+ });
+ }
+
+ private static Payload CreateZerosPayload(int size)
+ {
+ return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
new file mode 100644
index 0000000000..e9e659cb1f
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
@@ -0,0 +1,153 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Helper methods to start client runners for performance testing.
+ /// </summary>
+ public static class ClientRunners
+ {
+ /// <summary>
+ /// Creates a started client runner.
+ /// </summary>
+ public static IClientRunner CreateStarted(ClientConfig config)
+ {
+ string target = config.ServerTargets.Single();
+ Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
+
+ var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
+ var channel = new Channel(target, credentials);
+
+ switch (config.RpcType)
+ {
+ case RpcType.UNARY:
+ return new SyncUnaryClientRunner(channel,
+ config.PayloadConfig.SimpleParams.ReqSize,
+ config.HistogramParams);
+
+ case RpcType.STREAMING:
+ default:
+ throw new ArgumentException("Unsupported RpcType.");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Client that starts synchronous unary calls in a closed loop.
+ /// </summary>
+ public class SyncUnaryClientRunner : IClientRunner
+ {
+ const double SecondsToNanos = 1e9;
+
+ readonly Channel channel;
+ readonly int payloadSize;
+ readonly Histogram histogram;
+
+ readonly BenchmarkService.IBenchmarkServiceClient client;
+ readonly Task runnerTask;
+ readonly CancellationTokenSource stoppedCts;
+ readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+
+ public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams)
+ {
+ this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel);
+ this.payloadSize = payloadSize;
+ this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible);
+
+ this.stoppedCts = new CancellationTokenSource();
+ this.client = BenchmarkService.NewClient(channel);
+ this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
+ }
+
+ public ClientStats GetStats(bool reset)
+ {
+ var histogramData = histogram.GetSnapshot(reset);
+ var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
+
+ // TODO: populate user time and system time
+ return new ClientStats
+ {
+ Latencies = histogramData,
+ TimeElapsed = secondsElapsed,
+ TimeUser = 0,
+ TimeSystem = 0
+ };
+ }
+
+ public async Task StopAsync()
+ {
+ stoppedCts.Cancel();
+ await runnerTask;
+ await channel.ShutdownAsync();
+ }
+
+ private void Run()
+ {
+ var request = new SimpleRequest
+ {
+ Payload = CreateZerosPayload(payloadSize)
+ };
+ var stopwatch = new Stopwatch();
+
+ while (!stoppedCts.Token.IsCancellationRequested)
+ {
+ stopwatch.Restart();
+ client.UnaryCall(request);
+ stopwatch.Stop();
+
+ // spec requires data point in nanoseconds.
+ histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+ }
+ }
+
+ private static Payload CreateZerosPayload(int size)
+ {
+ return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs
new file mode 100644
index 0000000000..4764e1072b
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Control.cs
@@ -0,0 +1,2362 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test/proto/benchmarks/control.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Control {
+
+ #region Descriptor
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static Control() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiN0ZXN0L3Byb3RvL2JlbmNobWFya3MvY29udHJvbC5wcm90bxIMZ3JwYy50",
+ "ZXN0aW5nGiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8a",
+ "IXRlc3QvcHJvdG8vYmVuY2htYXJrcy9zdGF0cy5wcm90byIlCg1Qb2lzc29u",
+ "UGFyYW1zEhQKDG9mZmVyZWRfbG9hZBgBIAEoASJBCg1Vbmlmb3JtUGFyYW1z",
+ "EhcKD2ludGVyYXJyaXZhbF9sbxgBIAEoARIXCg9pbnRlcmFycml2YWxfaGkY",
+ "AiABKAEiKwoTRGV0ZXJtaW5pc3RpY1BhcmFtcxIUCgxvZmZlcmVkX2xvYWQY",
+ "ASABKAEiOAoMUGFyZXRvUGFyYW1zEhkKEWludGVyYXJyaXZhbF9iYXNlGAEg",
+ "ASgBEg0KBWFscGhhGAIgASgBIhIKEENsb3NlZExvb3BQYXJhbXMijgIKCkxv",
+ "YWRQYXJhbXMSNQoLY2xvc2VkX2xvb3AYASABKAsyHi5ncnBjLnRlc3Rpbmcu",
+ "Q2xvc2VkTG9vcFBhcmFtc0gAEi4KB3BvaXNzb24YAiABKAsyGy5ncnBjLnRl",
+ "c3RpbmcuUG9pc3NvblBhcmFtc0gAEi4KB3VuaWZvcm0YAyABKAsyGy5ncnBj",
+ "LnRlc3RpbmcuVW5pZm9ybVBhcmFtc0gAEjMKBmRldGVybRgEIAEoCzIhLmdy",
+ "cGMudGVzdGluZy5EZXRlcm1pbmlzdGljUGFyYW1zSAASLAoGcGFyZXRvGAUg",
+ "ASgLMhouZ3JwYy50ZXN0aW5nLlBhcmV0b1BhcmFtc0gAQgYKBGxvYWQiQwoO",
+ "U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy",
+ "X2hvc3Rfb3ZlcnJpZGUYAiABKAkirwMKDENsaWVudENvbmZpZxIWCg5zZXJ2",
+ "ZXJfdGFyZ2V0cxgBIAMoCRItCgtjbGllbnRfdHlwZRgCIAEoDjIYLmdycGMu",
+ "dGVzdGluZy5DbGllbnRUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgDIAEoCzIc",
+ "LmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIkChxvdXRzdGFuZGluZ19y",
+ "cGNzX3Blcl9jaGFubmVsGAQgASgFEhcKD2NsaWVudF9jaGFubmVscxgFIAEo",
+ "BRIcChRhc3luY19jbGllbnRfdGhyZWFkcxgHIAEoBRInCghycGNfdHlwZRgI",
+ "IAEoDjIVLmdycGMudGVzdGluZy5ScGNUeXBlEi0KC2xvYWRfcGFyYW1zGAog",
+ "ASgLMhguZ3JwYy50ZXN0aW5nLkxvYWRQYXJhbXMSMwoOcGF5bG9hZF9jb25m",
+ "aWcYCyABKAsyGy5ncnBjLnRlc3RpbmcuUGF5bG9hZENvbmZpZxI3ChBoaXN0",
+ "b2dyYW1fcGFyYW1zGAwgASgLMh0uZ3JwYy50ZXN0aW5nLkhpc3RvZ3JhbVBh",
+ "cmFtcyI4CgxDbGllbnRTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRl",
+ "c3RpbmcuQ2xpZW50U3RhdHMiFQoETWFyaxINCgVyZXNldBgBIAEoCCJoCgpD",
+ "bGllbnRBcmdzEisKBXNldHVwGAEgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVu",
+ "dENvbmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBjLnRlc3RpbmcuTWFya0gA",
+ "QgkKB2FyZ3R5cGUi9wEKDFNlcnZlckNvbmZpZxItCgtzZXJ2ZXJfdHlwZRgB",
+ "IAEoDjIYLmdycGMudGVzdGluZy5TZXJ2ZXJUeXBlEjUKD3NlY3VyaXR5X3Bh",
+ "cmFtcxgCIAEoCzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIMCgRo",
+ "b3N0GAMgASgJEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVyX3RocmVh",
+ "ZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2FkX2NvbmZp",
+ "ZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnImgKClNlcnZl",
+ "ckFyZ3MSKwoFc2V0dXAYASABKAsyGi5ncnBjLnRlc3RpbmcuU2VydmVyQ29u",
+ "ZmlnSAASIgoEbWFyaxgCIAEoCzISLmdycGMudGVzdGluZy5NYXJrSABCCQoH",
+ "YXJndHlwZSJVCgxTZXJ2ZXJTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBj",
+ "LnRlc3RpbmcuU2VydmVyU3RhdHMSDAoEcG9ydBgCIAEoBRINCgVjb3JlcxgD",
+ "IAEoBSovCgpDbGllbnRUeXBlEg8KC1NZTkNfQ0xJRU5UEAASEAoMQVNZTkNf",
+ "Q0xJRU5UEAEqLwoKU2VydmVyVHlwZRIPCgtTWU5DX1NFUlZFUhAAEhAKDEFT",
+ "WU5DX1NFUlZFUhABKiMKB1JwY1R5cGUSCQoFVU5BUlkQABINCglTVFJFQU1J",
+ "TkcQAWIGcHJvdG8z"));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { global::Grpc.Testing.Payloads.Descriptor, global::Grpc.Testing.Stats.Descriptor, },
+ new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PoissonParams), new[]{ "OfferedLoad" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.UniformParams), new[]{ "InterarrivalLo", "InterarrivalHi" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.DeterministicParams), new[]{ "OfferedLoad" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ParetoParams), new[]{ "InterarrivalBase", "Alpha" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClosedLoopParams), null, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.LoadParams), new[]{ "ClosedLoop", "Poisson", "Uniform", "Determ", "Pareto" }, new[]{ "Load" }, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SecurityParams), new[]{ "UseTestCa", "ServerHostOverride" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientConfig), new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStatus), new[]{ "Stats" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Mark), new[]{ "Reset" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientArgs), new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerConfig), new[]{ "ServerType", "SecurityParams", "Host", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerArgs), new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStatus), new[]{ "Stats", "Port", "Cores" }, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Enums
+ public enum ClientType {
+ SYNC_CLIENT = 0,
+ ASYNC_CLIENT = 1,
+ }
+
+ public enum ServerType {
+ SYNC_SERVER = 0,
+ ASYNC_SERVER = 1,
+ }
+
+ public enum RpcType {
+ UNARY = 0,
+ STREAMING = 1,
+ }
+
+ #endregion
+
+ #region Messages
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class PoissonParams : pb::IMessage<PoissonParams> {
+ private static readonly pb::MessageParser<PoissonParams> _parser = new pb::MessageParser<PoissonParams>(() => new PoissonParams());
+ public static pb::MessageParser<PoissonParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[0]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public PoissonParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public PoissonParams(PoissonParams other) : this() {
+ offeredLoad_ = other.offeredLoad_;
+ }
+
+ public PoissonParams Clone() {
+ return new PoissonParams(this);
+ }
+
+ public const int OfferedLoadFieldNumber = 1;
+ private double offeredLoad_;
+ public double OfferedLoad {
+ get { return offeredLoad_; }
+ set {
+ offeredLoad_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as PoissonParams);
+ }
+
+ public bool Equals(PoissonParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (OfferedLoad != other.OfferedLoad) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (OfferedLoad != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(OfferedLoad);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (OfferedLoad != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(PoissonParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.OfferedLoad != 0D) {
+ OfferedLoad = other.OfferedLoad;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ OfferedLoad = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class UniformParams : pb::IMessage<UniformParams> {
+ private static readonly pb::MessageParser<UniformParams> _parser = new pb::MessageParser<UniformParams>(() => new UniformParams());
+ public static pb::MessageParser<UniformParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public UniformParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public UniformParams(UniformParams other) : this() {
+ interarrivalLo_ = other.interarrivalLo_;
+ interarrivalHi_ = other.interarrivalHi_;
+ }
+
+ public UniformParams Clone() {
+ return new UniformParams(this);
+ }
+
+ public const int InterarrivalLoFieldNumber = 1;
+ private double interarrivalLo_;
+ public double InterarrivalLo {
+ get { return interarrivalLo_; }
+ set {
+ interarrivalLo_ = value;
+ }
+ }
+
+ public const int InterarrivalHiFieldNumber = 2;
+ private double interarrivalHi_;
+ public double InterarrivalHi {
+ get { return interarrivalHi_; }
+ set {
+ interarrivalHi_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as UniformParams);
+ }
+
+ public bool Equals(UniformParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (InterarrivalLo != other.InterarrivalLo) return false;
+ if (InterarrivalHi != other.InterarrivalHi) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (InterarrivalLo != 0D) hash ^= InterarrivalLo.GetHashCode();
+ if (InterarrivalHi != 0D) hash ^= InterarrivalHi.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (InterarrivalLo != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(InterarrivalLo);
+ }
+ if (InterarrivalHi != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(InterarrivalHi);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (InterarrivalLo != 0D) {
+ size += 1 + 8;
+ }
+ if (InterarrivalHi != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(UniformParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.InterarrivalLo != 0D) {
+ InterarrivalLo = other.InterarrivalLo;
+ }
+ if (other.InterarrivalHi != 0D) {
+ InterarrivalHi = other.InterarrivalHi;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ InterarrivalLo = input.ReadDouble();
+ break;
+ }
+ case 17: {
+ InterarrivalHi = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class DeterministicParams : pb::IMessage<DeterministicParams> {
+ private static readonly pb::MessageParser<DeterministicParams> _parser = new pb::MessageParser<DeterministicParams>(() => new DeterministicParams());
+ public static pb::MessageParser<DeterministicParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[2]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public DeterministicParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public DeterministicParams(DeterministicParams other) : this() {
+ offeredLoad_ = other.offeredLoad_;
+ }
+
+ public DeterministicParams Clone() {
+ return new DeterministicParams(this);
+ }
+
+ public const int OfferedLoadFieldNumber = 1;
+ private double offeredLoad_;
+ public double OfferedLoad {
+ get { return offeredLoad_; }
+ set {
+ offeredLoad_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as DeterministicParams);
+ }
+
+ public bool Equals(DeterministicParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (OfferedLoad != other.OfferedLoad) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (OfferedLoad != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(OfferedLoad);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (OfferedLoad != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(DeterministicParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.OfferedLoad != 0D) {
+ OfferedLoad = other.OfferedLoad;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ OfferedLoad = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ParetoParams : pb::IMessage<ParetoParams> {
+ private static readonly pb::MessageParser<ParetoParams> _parser = new pb::MessageParser<ParetoParams>(() => new ParetoParams());
+ public static pb::MessageParser<ParetoParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[3]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ParetoParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ParetoParams(ParetoParams other) : this() {
+ interarrivalBase_ = other.interarrivalBase_;
+ alpha_ = other.alpha_;
+ }
+
+ public ParetoParams Clone() {
+ return new ParetoParams(this);
+ }
+
+ public const int InterarrivalBaseFieldNumber = 1;
+ private double interarrivalBase_;
+ public double InterarrivalBase {
+ get { return interarrivalBase_; }
+ set {
+ interarrivalBase_ = value;
+ }
+ }
+
+ public const int AlphaFieldNumber = 2;
+ private double alpha_;
+ public double Alpha {
+ get { return alpha_; }
+ set {
+ alpha_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ParetoParams);
+ }
+
+ public bool Equals(ParetoParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (InterarrivalBase != other.InterarrivalBase) return false;
+ if (Alpha != other.Alpha) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (InterarrivalBase != 0D) hash ^= InterarrivalBase.GetHashCode();
+ if (Alpha != 0D) hash ^= Alpha.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (InterarrivalBase != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(InterarrivalBase);
+ }
+ if (Alpha != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(Alpha);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (InterarrivalBase != 0D) {
+ size += 1 + 8;
+ }
+ if (Alpha != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(ParetoParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.InterarrivalBase != 0D) {
+ InterarrivalBase = other.InterarrivalBase;
+ }
+ if (other.Alpha != 0D) {
+ Alpha = other.Alpha;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ InterarrivalBase = input.ReadDouble();
+ break;
+ }
+ case 17: {
+ Alpha = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ClosedLoopParams : pb::IMessage<ClosedLoopParams> {
+ private static readonly pb::MessageParser<ClosedLoopParams> _parser = new pb::MessageParser<ClosedLoopParams>(() => new ClosedLoopParams());
+ public static pb::MessageParser<ClosedLoopParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[4]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ClosedLoopParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ClosedLoopParams(ClosedLoopParams other) : this() {
+ }
+
+ public ClosedLoopParams Clone() {
+ return new ClosedLoopParams(this);
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ClosedLoopParams);
+ }
+
+ public bool Equals(ClosedLoopParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ return size;
+ }
+
+ public void MergeFrom(ClosedLoopParams other) {
+ if (other == null) {
+ return;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class LoadParams : pb::IMessage<LoadParams> {
+ private static readonly pb::MessageParser<LoadParams> _parser = new pb::MessageParser<LoadParams>(() => new LoadParams());
+ public static pb::MessageParser<LoadParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[5]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public LoadParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public LoadParams(LoadParams other) : this() {
+ switch (other.LoadCase) {
+ case LoadOneofCase.ClosedLoop:
+ ClosedLoop = other.ClosedLoop.Clone();
+ break;
+ case LoadOneofCase.Poisson:
+ Poisson = other.Poisson.Clone();
+ break;
+ case LoadOneofCase.Uniform:
+ Uniform = other.Uniform.Clone();
+ break;
+ case LoadOneofCase.Determ:
+ Determ = other.Determ.Clone();
+ break;
+ case LoadOneofCase.Pareto:
+ Pareto = other.Pareto.Clone();
+ break;
+ }
+
+ }
+
+ public LoadParams Clone() {
+ return new LoadParams(this);
+ }
+
+ public const int ClosedLoopFieldNumber = 1;
+ public global::Grpc.Testing.ClosedLoopParams ClosedLoop {
+ get { return loadCase_ == LoadOneofCase.ClosedLoop ? (global::Grpc.Testing.ClosedLoopParams) load_ : null; }
+ set {
+ load_ = value;
+ loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.ClosedLoop;
+ }
+ }
+
+ public const int PoissonFieldNumber = 2;
+ public global::Grpc.Testing.PoissonParams Poisson {
+ get { return loadCase_ == LoadOneofCase.Poisson ? (global::Grpc.Testing.PoissonParams) load_ : null; }
+ set {
+ load_ = value;
+ loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Poisson;
+ }
+ }
+
+ public const int UniformFieldNumber = 3;
+ public global::Grpc.Testing.UniformParams Uniform {
+ get { return loadCase_ == LoadOneofCase.Uniform ? (global::Grpc.Testing.UniformParams) load_ : null; }
+ set {
+ load_ = value;
+ loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Uniform;
+ }
+ }
+
+ public const int DetermFieldNumber = 4;
+ public global::Grpc.Testing.DeterministicParams Determ {
+ get { return loadCase_ == LoadOneofCase.Determ ? (global::Grpc.Testing.DeterministicParams) load_ : null; }
+ set {
+ load_ = value;
+ loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Determ;
+ }
+ }
+
+ public const int ParetoFieldNumber = 5;
+ public global::Grpc.Testing.ParetoParams Pareto {
+ get { return loadCase_ == LoadOneofCase.Pareto ? (global::Grpc.Testing.ParetoParams) load_ : null; }
+ set {
+ load_ = value;
+ loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Pareto;
+ }
+ }
+
+ private object load_;
+ public enum LoadOneofCase {
+ None = 0,
+ ClosedLoop = 1,
+ Poisson = 2,
+ Uniform = 3,
+ Determ = 4,
+ Pareto = 5,
+ }
+ private LoadOneofCase loadCase_ = LoadOneofCase.None;
+ public LoadOneofCase LoadCase {
+ get { return loadCase_; }
+ }
+
+ public void ClearLoad() {
+ loadCase_ = LoadOneofCase.None;
+ load_ = null;
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as LoadParams);
+ }
+
+ public bool Equals(LoadParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(ClosedLoop, other.ClosedLoop)) return false;
+ if (!object.Equals(Poisson, other.Poisson)) return false;
+ if (!object.Equals(Uniform, other.Uniform)) return false;
+ if (!object.Equals(Determ, other.Determ)) return false;
+ if (!object.Equals(Pareto, other.Pareto)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (loadCase_ == LoadOneofCase.ClosedLoop) hash ^= ClosedLoop.GetHashCode();
+ if (loadCase_ == LoadOneofCase.Poisson) hash ^= Poisson.GetHashCode();
+ if (loadCase_ == LoadOneofCase.Uniform) hash ^= Uniform.GetHashCode();
+ if (loadCase_ == LoadOneofCase.Determ) hash ^= Determ.GetHashCode();
+ if (loadCase_ == LoadOneofCase.Pareto) hash ^= Pareto.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (loadCase_ == LoadOneofCase.ClosedLoop) {
+ output.WriteRawTag(10);
+ output.WriteMessage(ClosedLoop);
+ }
+ if (loadCase_ == LoadOneofCase.Poisson) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Poisson);
+ }
+ if (loadCase_ == LoadOneofCase.Uniform) {
+ output.WriteRawTag(26);
+ output.WriteMessage(Uniform);
+ }
+ if (loadCase_ == LoadOneofCase.Determ) {
+ output.WriteRawTag(34);
+ output.WriteMessage(Determ);
+ }
+ if (loadCase_ == LoadOneofCase.Pareto) {
+ output.WriteRawTag(42);
+ output.WriteMessage(Pareto);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (loadCase_ == LoadOneofCase.ClosedLoop) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ClosedLoop);
+ }
+ if (loadCase_ == LoadOneofCase.Poisson) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Poisson);
+ }
+ if (loadCase_ == LoadOneofCase.Uniform) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Uniform);
+ }
+ if (loadCase_ == LoadOneofCase.Determ) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Determ);
+ }
+ if (loadCase_ == LoadOneofCase.Pareto) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pareto);
+ }
+ return size;
+ }
+
+ public void MergeFrom(LoadParams other) {
+ if (other == null) {
+ return;
+ }
+ switch (other.LoadCase) {
+ case LoadOneofCase.ClosedLoop:
+ ClosedLoop = other.ClosedLoop;
+ break;
+ case LoadOneofCase.Poisson:
+ Poisson = other.Poisson;
+ break;
+ case LoadOneofCase.Uniform:
+ Uniform = other.Uniform;
+ break;
+ case LoadOneofCase.Determ:
+ Determ = other.Determ;
+ break;
+ case LoadOneofCase.Pareto:
+ Pareto = other.Pareto;
+ break;
+ }
+
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ global::Grpc.Testing.ClosedLoopParams subBuilder = new global::Grpc.Testing.ClosedLoopParams();
+ if (loadCase_ == LoadOneofCase.ClosedLoop) {
+ subBuilder.MergeFrom(ClosedLoop);
+ }
+ input.ReadMessage(subBuilder);
+ ClosedLoop = subBuilder;
+ break;
+ }
+ case 18: {
+ global::Grpc.Testing.PoissonParams subBuilder = new global::Grpc.Testing.PoissonParams();
+ if (loadCase_ == LoadOneofCase.Poisson) {
+ subBuilder.MergeFrom(Poisson);
+ }
+ input.ReadMessage(subBuilder);
+ Poisson = subBuilder;
+ break;
+ }
+ case 26: {
+ global::Grpc.Testing.UniformParams subBuilder = new global::Grpc.Testing.UniformParams();
+ if (loadCase_ == LoadOneofCase.Uniform) {
+ subBuilder.MergeFrom(Uniform);
+ }
+ input.ReadMessage(subBuilder);
+ Uniform = subBuilder;
+ break;
+ }
+ case 34: {
+ global::Grpc.Testing.DeterministicParams subBuilder = new global::Grpc.Testing.DeterministicParams();
+ if (loadCase_ == LoadOneofCase.Determ) {
+ subBuilder.MergeFrom(Determ);
+ }
+ input.ReadMessage(subBuilder);
+ Determ = subBuilder;
+ break;
+ }
+ case 42: {
+ global::Grpc.Testing.ParetoParams subBuilder = new global::Grpc.Testing.ParetoParams();
+ if (loadCase_ == LoadOneofCase.Pareto) {
+ subBuilder.MergeFrom(Pareto);
+ }
+ input.ReadMessage(subBuilder);
+ Pareto = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class SecurityParams : pb::IMessage<SecurityParams> {
+ private static readonly pb::MessageParser<SecurityParams> _parser = new pb::MessageParser<SecurityParams>(() => new SecurityParams());
+ public static pb::MessageParser<SecurityParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[6]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public SecurityParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public SecurityParams(SecurityParams other) : this() {
+ useTestCa_ = other.useTestCa_;
+ serverHostOverride_ = other.serverHostOverride_;
+ }
+
+ public SecurityParams Clone() {
+ return new SecurityParams(this);
+ }
+
+ public const int UseTestCaFieldNumber = 1;
+ private bool useTestCa_;
+ public bool UseTestCa {
+ get { return useTestCa_; }
+ set {
+ useTestCa_ = value;
+ }
+ }
+
+ public const int ServerHostOverrideFieldNumber = 2;
+ private string serverHostOverride_ = "";
+ public string ServerHostOverride {
+ get { return serverHostOverride_; }
+ set {
+ serverHostOverride_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as SecurityParams);
+ }
+
+ public bool Equals(SecurityParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (UseTestCa != other.UseTestCa) return false;
+ if (ServerHostOverride != other.ServerHostOverride) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (UseTestCa != false) hash ^= UseTestCa.GetHashCode();
+ if (ServerHostOverride.Length != 0) hash ^= ServerHostOverride.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (UseTestCa != false) {
+ output.WriteRawTag(8);
+ output.WriteBool(UseTestCa);
+ }
+ if (ServerHostOverride.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(ServerHostOverride);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (UseTestCa != false) {
+ size += 1 + 1;
+ }
+ if (ServerHostOverride.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ServerHostOverride);
+ }
+ return size;
+ }
+
+ public void MergeFrom(SecurityParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.UseTestCa != false) {
+ UseTestCa = other.UseTestCa;
+ }
+ if (other.ServerHostOverride.Length != 0) {
+ ServerHostOverride = other.ServerHostOverride;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ UseTestCa = input.ReadBool();
+ break;
+ }
+ case 18: {
+ ServerHostOverride = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ClientConfig : pb::IMessage<ClientConfig> {
+ private static readonly pb::MessageParser<ClientConfig> _parser = new pb::MessageParser<ClientConfig>(() => new ClientConfig());
+ public static pb::MessageParser<ClientConfig> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[7]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ClientConfig() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ClientConfig(ClientConfig other) : this() {
+ serverTargets_ = other.serverTargets_.Clone();
+ clientType_ = other.clientType_;
+ SecurityParams = other.securityParams_ != null ? other.SecurityParams.Clone() : null;
+ outstandingRpcsPerChannel_ = other.outstandingRpcsPerChannel_;
+ clientChannels_ = other.clientChannels_;
+ asyncClientThreads_ = other.asyncClientThreads_;
+ rpcType_ = other.rpcType_;
+ LoadParams = other.loadParams_ != null ? other.LoadParams.Clone() : null;
+ PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null;
+ HistogramParams = other.histogramParams_ != null ? other.HistogramParams.Clone() : null;
+ }
+
+ public ClientConfig Clone() {
+ return new ClientConfig(this);
+ }
+
+ public const int ServerTargetsFieldNumber = 1;
+ private static readonly pb::FieldCodec<string> _repeated_serverTargets_codec
+ = pb::FieldCodec.ForString(10);
+ private readonly pbc::RepeatedField<string> serverTargets_ = new pbc::RepeatedField<string>();
+ public pbc::RepeatedField<string> ServerTargets {
+ get { return serverTargets_; }
+ }
+
+ public const int ClientTypeFieldNumber = 2;
+ private global::Grpc.Testing.ClientType clientType_ = global::Grpc.Testing.ClientType.SYNC_CLIENT;
+ public global::Grpc.Testing.ClientType ClientType {
+ get { return clientType_; }
+ set {
+ clientType_ = value;
+ }
+ }
+
+ public const int SecurityParamsFieldNumber = 3;
+ private global::Grpc.Testing.SecurityParams securityParams_;
+ public global::Grpc.Testing.SecurityParams SecurityParams {
+ get { return securityParams_; }
+ set {
+ securityParams_ = value;
+ }
+ }
+
+ public const int OutstandingRpcsPerChannelFieldNumber = 4;
+ private int outstandingRpcsPerChannel_;
+ public int OutstandingRpcsPerChannel {
+ get { return outstandingRpcsPerChannel_; }
+ set {
+ outstandingRpcsPerChannel_ = value;
+ }
+ }
+
+ public const int ClientChannelsFieldNumber = 5;
+ private int clientChannels_;
+ public int ClientChannels {
+ get { return clientChannels_; }
+ set {
+ clientChannels_ = value;
+ }
+ }
+
+ public const int AsyncClientThreadsFieldNumber = 7;
+ private int asyncClientThreads_;
+ public int AsyncClientThreads {
+ get { return asyncClientThreads_; }
+ set {
+ asyncClientThreads_ = value;
+ }
+ }
+
+ public const int RpcTypeFieldNumber = 8;
+ private global::Grpc.Testing.RpcType rpcType_ = global::Grpc.Testing.RpcType.UNARY;
+ public global::Grpc.Testing.RpcType RpcType {
+ get { return rpcType_; }
+ set {
+ rpcType_ = value;
+ }
+ }
+
+ public const int LoadParamsFieldNumber = 10;
+ private global::Grpc.Testing.LoadParams loadParams_;
+ public global::Grpc.Testing.LoadParams LoadParams {
+ get { return loadParams_; }
+ set {
+ loadParams_ = value;
+ }
+ }
+
+ public const int PayloadConfigFieldNumber = 11;
+ private global::Grpc.Testing.PayloadConfig payloadConfig_;
+ public global::Grpc.Testing.PayloadConfig PayloadConfig {
+ get { return payloadConfig_; }
+ set {
+ payloadConfig_ = value;
+ }
+ }
+
+ public const int HistogramParamsFieldNumber = 12;
+ private global::Grpc.Testing.HistogramParams histogramParams_;
+ public global::Grpc.Testing.HistogramParams HistogramParams {
+ get { return histogramParams_; }
+ set {
+ histogramParams_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ClientConfig);
+ }
+
+ public bool Equals(ClientConfig other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!serverTargets_.Equals(other.serverTargets_)) return false;
+ if (ClientType != other.ClientType) return false;
+ if (!object.Equals(SecurityParams, other.SecurityParams)) return false;
+ if (OutstandingRpcsPerChannel != other.OutstandingRpcsPerChannel) return false;
+ if (ClientChannels != other.ClientChannels) return false;
+ if (AsyncClientThreads != other.AsyncClientThreads) return false;
+ if (RpcType != other.RpcType) return false;
+ if (!object.Equals(LoadParams, other.LoadParams)) return false;
+ if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false;
+ if (!object.Equals(HistogramParams, other.HistogramParams)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= serverTargets_.GetHashCode();
+ if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) hash ^= ClientType.GetHashCode();
+ if (securityParams_ != null) hash ^= SecurityParams.GetHashCode();
+ if (OutstandingRpcsPerChannel != 0) hash ^= OutstandingRpcsPerChannel.GetHashCode();
+ if (ClientChannels != 0) hash ^= ClientChannels.GetHashCode();
+ if (AsyncClientThreads != 0) hash ^= AsyncClientThreads.GetHashCode();
+ if (RpcType != global::Grpc.Testing.RpcType.UNARY) hash ^= RpcType.GetHashCode();
+ if (loadParams_ != null) hash ^= LoadParams.GetHashCode();
+ if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode();
+ if (histogramParams_ != null) hash ^= HistogramParams.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ serverTargets_.WriteTo(output, _repeated_serverTargets_codec);
+ if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ output.WriteRawTag(16);
+ output.WriteEnum((int) ClientType);
+ }
+ if (securityParams_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(SecurityParams);
+ }
+ if (OutstandingRpcsPerChannel != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(OutstandingRpcsPerChannel);
+ }
+ if (ClientChannels != 0) {
+ output.WriteRawTag(40);
+ output.WriteInt32(ClientChannels);
+ }
+ if (AsyncClientThreads != 0) {
+ output.WriteRawTag(56);
+ output.WriteInt32(AsyncClientThreads);
+ }
+ if (RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ output.WriteRawTag(64);
+ output.WriteEnum((int) RpcType);
+ }
+ if (loadParams_ != null) {
+ output.WriteRawTag(82);
+ output.WriteMessage(LoadParams);
+ }
+ if (payloadConfig_ != null) {
+ output.WriteRawTag(90);
+ output.WriteMessage(PayloadConfig);
+ }
+ if (histogramParams_ != null) {
+ output.WriteRawTag(98);
+ output.WriteMessage(HistogramParams);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ size += serverTargets_.CalculateSize(_repeated_serverTargets_codec);
+ if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ClientType);
+ }
+ if (securityParams_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(SecurityParams);
+ }
+ if (OutstandingRpcsPerChannel != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(OutstandingRpcsPerChannel);
+ }
+ if (ClientChannels != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ClientChannels);
+ }
+ if (AsyncClientThreads != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(AsyncClientThreads);
+ }
+ if (RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RpcType);
+ }
+ if (loadParams_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(LoadParams);
+ }
+ if (payloadConfig_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(PayloadConfig);
+ }
+ if (histogramParams_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(HistogramParams);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ClientConfig other) {
+ if (other == null) {
+ return;
+ }
+ serverTargets_.Add(other.serverTargets_);
+ if (other.ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ ClientType = other.ClientType;
+ }
+ if (other.securityParams_ != null) {
+ if (securityParams_ == null) {
+ securityParams_ = new global::Grpc.Testing.SecurityParams();
+ }
+ SecurityParams.MergeFrom(other.SecurityParams);
+ }
+ if (other.OutstandingRpcsPerChannel != 0) {
+ OutstandingRpcsPerChannel = other.OutstandingRpcsPerChannel;
+ }
+ if (other.ClientChannels != 0) {
+ ClientChannels = other.ClientChannels;
+ }
+ if (other.AsyncClientThreads != 0) {
+ AsyncClientThreads = other.AsyncClientThreads;
+ }
+ if (other.RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ RpcType = other.RpcType;
+ }
+ if (other.loadParams_ != null) {
+ if (loadParams_ == null) {
+ loadParams_ = new global::Grpc.Testing.LoadParams();
+ }
+ LoadParams.MergeFrom(other.LoadParams);
+ }
+ if (other.payloadConfig_ != null) {
+ if (payloadConfig_ == null) {
+ payloadConfig_ = new global::Grpc.Testing.PayloadConfig();
+ }
+ PayloadConfig.MergeFrom(other.PayloadConfig);
+ }
+ if (other.histogramParams_ != null) {
+ if (histogramParams_ == null) {
+ histogramParams_ = new global::Grpc.Testing.HistogramParams();
+ }
+ HistogramParams.MergeFrom(other.HistogramParams);
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ serverTargets_.AddEntriesFrom(input, _repeated_serverTargets_codec);
+ break;
+ }
+ case 16: {
+ clientType_ = (global::Grpc.Testing.ClientType) input.ReadEnum();
+ break;
+ }
+ case 26: {
+ if (securityParams_ == null) {
+ securityParams_ = new global::Grpc.Testing.SecurityParams();
+ }
+ input.ReadMessage(securityParams_);
+ break;
+ }
+ case 32: {
+ OutstandingRpcsPerChannel = input.ReadInt32();
+ break;
+ }
+ case 40: {
+ ClientChannels = input.ReadInt32();
+ break;
+ }
+ case 56: {
+ AsyncClientThreads = input.ReadInt32();
+ break;
+ }
+ case 64: {
+ rpcType_ = (global::Grpc.Testing.RpcType) input.ReadEnum();
+ break;
+ }
+ case 82: {
+ if (loadParams_ == null) {
+ loadParams_ = new global::Grpc.Testing.LoadParams();
+ }
+ input.ReadMessage(loadParams_);
+ break;
+ }
+ case 90: {
+ if (payloadConfig_ == null) {
+ payloadConfig_ = new global::Grpc.Testing.PayloadConfig();
+ }
+ input.ReadMessage(payloadConfig_);
+ break;
+ }
+ case 98: {
+ if (histogramParams_ == null) {
+ histogramParams_ = new global::Grpc.Testing.HistogramParams();
+ }
+ input.ReadMessage(histogramParams_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ClientStatus : pb::IMessage<ClientStatus> {
+ private static readonly pb::MessageParser<ClientStatus> _parser = new pb::MessageParser<ClientStatus>(() => new ClientStatus());
+ public static pb::MessageParser<ClientStatus> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[8]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ClientStatus() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ClientStatus(ClientStatus other) : this() {
+ Stats = other.stats_ != null ? other.Stats.Clone() : null;
+ }
+
+ public ClientStatus Clone() {
+ return new ClientStatus(this);
+ }
+
+ public const int StatsFieldNumber = 1;
+ private global::Grpc.Testing.ClientStats stats_;
+ public global::Grpc.Testing.ClientStats Stats {
+ get { return stats_; }
+ set {
+ stats_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ClientStatus);
+ }
+
+ public bool Equals(ClientStatus other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Stats, other.Stats)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (stats_ != null) hash ^= Stats.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (stats_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Stats);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (stats_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stats);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ClientStatus other) {
+ if (other == null) {
+ return;
+ }
+ if (other.stats_ != null) {
+ if (stats_ == null) {
+ stats_ = new global::Grpc.Testing.ClientStats();
+ }
+ Stats.MergeFrom(other.Stats);
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (stats_ == null) {
+ stats_ = new global::Grpc.Testing.ClientStats();
+ }
+ input.ReadMessage(stats_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Mark : pb::IMessage<Mark> {
+ private static readonly pb::MessageParser<Mark> _parser = new pb::MessageParser<Mark>(() => new Mark());
+ public static pb::MessageParser<Mark> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[9]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public Mark() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public Mark(Mark other) : this() {
+ reset_ = other.reset_;
+ }
+
+ public Mark Clone() {
+ return new Mark(this);
+ }
+
+ public const int ResetFieldNumber = 1;
+ private bool reset_;
+ public bool Reset {
+ get { return reset_; }
+ set {
+ reset_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as Mark);
+ }
+
+ public bool Equals(Mark other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Reset != other.Reset) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Reset != false) hash ^= Reset.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Reset != false) {
+ output.WriteRawTag(8);
+ output.WriteBool(Reset);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Reset != false) {
+ size += 1 + 1;
+ }
+ return size;
+ }
+
+ public void MergeFrom(Mark other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Reset != false) {
+ Reset = other.Reset;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Reset = input.ReadBool();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ClientArgs : pb::IMessage<ClientArgs> {
+ private static readonly pb::MessageParser<ClientArgs> _parser = new pb::MessageParser<ClientArgs>(() => new ClientArgs());
+ public static pb::MessageParser<ClientArgs> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[10]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ClientArgs() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ClientArgs(ClientArgs other) : this() {
+ switch (other.ArgtypeCase) {
+ case ArgtypeOneofCase.Setup:
+ Setup = other.Setup.Clone();
+ break;
+ case ArgtypeOneofCase.Mark:
+ Mark = other.Mark.Clone();
+ break;
+ }
+
+ }
+
+ public ClientArgs Clone() {
+ return new ClientArgs(this);
+ }
+
+ public const int SetupFieldNumber = 1;
+ public global::Grpc.Testing.ClientConfig Setup {
+ get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ClientConfig) argtype_ : null; }
+ set {
+ argtype_ = value;
+ argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Setup;
+ }
+ }
+
+ public const int MarkFieldNumber = 2;
+ public global::Grpc.Testing.Mark Mark {
+ get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; }
+ set {
+ argtype_ = value;
+ argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Mark;
+ }
+ }
+
+ private object argtype_;
+ public enum ArgtypeOneofCase {
+ None = 0,
+ Setup = 1,
+ Mark = 2,
+ }
+ private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None;
+ public ArgtypeOneofCase ArgtypeCase {
+ get { return argtypeCase_; }
+ }
+
+ public void ClearArgtype() {
+ argtypeCase_ = ArgtypeOneofCase.None;
+ argtype_ = null;
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ClientArgs);
+ }
+
+ public bool Equals(ClientArgs other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Setup, other.Setup)) return false;
+ if (!object.Equals(Mark, other.Mark)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode();
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) hash ^= Mark.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Setup);
+ }
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Mark);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Setup);
+ }
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mark);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ClientArgs other) {
+ if (other == null) {
+ return;
+ }
+ switch (other.ArgtypeCase) {
+ case ArgtypeOneofCase.Setup:
+ Setup = other.Setup;
+ break;
+ case ArgtypeOneofCase.Mark:
+ Mark = other.Mark;
+ break;
+ }
+
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ global::Grpc.Testing.ClientConfig subBuilder = new global::Grpc.Testing.ClientConfig();
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ subBuilder.MergeFrom(Setup);
+ }
+ input.ReadMessage(subBuilder);
+ Setup = subBuilder;
+ break;
+ }
+ case 18: {
+ global::Grpc.Testing.Mark subBuilder = new global::Grpc.Testing.Mark();
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ subBuilder.MergeFrom(Mark);
+ }
+ input.ReadMessage(subBuilder);
+ Mark = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ServerConfig : pb::IMessage<ServerConfig> {
+ private static readonly pb::MessageParser<ServerConfig> _parser = new pb::MessageParser<ServerConfig>(() => new ServerConfig());
+ public static pb::MessageParser<ServerConfig> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[11]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ServerConfig() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ServerConfig(ServerConfig other) : this() {
+ serverType_ = other.serverType_;
+ SecurityParams = other.securityParams_ != null ? other.SecurityParams.Clone() : null;
+ host_ = other.host_;
+ port_ = other.port_;
+ asyncServerThreads_ = other.asyncServerThreads_;
+ coreLimit_ = other.coreLimit_;
+ PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null;
+ }
+
+ public ServerConfig Clone() {
+ return new ServerConfig(this);
+ }
+
+ public const int ServerTypeFieldNumber = 1;
+ private global::Grpc.Testing.ServerType serverType_ = global::Grpc.Testing.ServerType.SYNC_SERVER;
+ public global::Grpc.Testing.ServerType ServerType {
+ get { return serverType_; }
+ set {
+ serverType_ = value;
+ }
+ }
+
+ public const int SecurityParamsFieldNumber = 2;
+ private global::Grpc.Testing.SecurityParams securityParams_;
+ public global::Grpc.Testing.SecurityParams SecurityParams {
+ get { return securityParams_; }
+ set {
+ securityParams_ = value;
+ }
+ }
+
+ public const int HostFieldNumber = 3;
+ private string host_ = "";
+ public string Host {
+ get { return host_; }
+ set {
+ host_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ public const int PortFieldNumber = 4;
+ private int port_;
+ public int Port {
+ get { return port_; }
+ set {
+ port_ = value;
+ }
+ }
+
+ public const int AsyncServerThreadsFieldNumber = 7;
+ private int asyncServerThreads_;
+ public int AsyncServerThreads {
+ get { return asyncServerThreads_; }
+ set {
+ asyncServerThreads_ = value;
+ }
+ }
+
+ public const int CoreLimitFieldNumber = 8;
+ private int coreLimit_;
+ public int CoreLimit {
+ get { return coreLimit_; }
+ set {
+ coreLimit_ = value;
+ }
+ }
+
+ public const int PayloadConfigFieldNumber = 9;
+ private global::Grpc.Testing.PayloadConfig payloadConfig_;
+ public global::Grpc.Testing.PayloadConfig PayloadConfig {
+ get { return payloadConfig_; }
+ set {
+ payloadConfig_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ServerConfig);
+ }
+
+ public bool Equals(ServerConfig other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ServerType != other.ServerType) return false;
+ if (!object.Equals(SecurityParams, other.SecurityParams)) return false;
+ if (Host != other.Host) return false;
+ if (Port != other.Port) return false;
+ if (AsyncServerThreads != other.AsyncServerThreads) return false;
+ if (CoreLimit != other.CoreLimit) return false;
+ if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) hash ^= ServerType.GetHashCode();
+ if (securityParams_ != null) hash ^= SecurityParams.GetHashCode();
+ if (Host.Length != 0) hash ^= Host.GetHashCode();
+ if (Port != 0) hash ^= Port.GetHashCode();
+ if (AsyncServerThreads != 0) hash ^= AsyncServerThreads.GetHashCode();
+ if (CoreLimit != 0) hash ^= CoreLimit.GetHashCode();
+ if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ output.WriteRawTag(8);
+ output.WriteEnum((int) ServerType);
+ }
+ if (securityParams_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(SecurityParams);
+ }
+ if (Host.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(Host);
+ }
+ if (Port != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(Port);
+ }
+ if (AsyncServerThreads != 0) {
+ output.WriteRawTag(56);
+ output.WriteInt32(AsyncServerThreads);
+ }
+ if (CoreLimit != 0) {
+ output.WriteRawTag(64);
+ output.WriteInt32(CoreLimit);
+ }
+ if (payloadConfig_ != null) {
+ output.WriteRawTag(74);
+ output.WriteMessage(PayloadConfig);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ServerType);
+ }
+ if (securityParams_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(SecurityParams);
+ }
+ if (Host.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Host);
+ }
+ if (Port != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port);
+ }
+ if (AsyncServerThreads != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(AsyncServerThreads);
+ }
+ if (CoreLimit != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(CoreLimit);
+ }
+ if (payloadConfig_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(PayloadConfig);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ServerConfig other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ ServerType = other.ServerType;
+ }
+ if (other.securityParams_ != null) {
+ if (securityParams_ == null) {
+ securityParams_ = new global::Grpc.Testing.SecurityParams();
+ }
+ SecurityParams.MergeFrom(other.SecurityParams);
+ }
+ if (other.Host.Length != 0) {
+ Host = other.Host;
+ }
+ if (other.Port != 0) {
+ Port = other.Port;
+ }
+ if (other.AsyncServerThreads != 0) {
+ AsyncServerThreads = other.AsyncServerThreads;
+ }
+ if (other.CoreLimit != 0) {
+ CoreLimit = other.CoreLimit;
+ }
+ if (other.payloadConfig_ != null) {
+ if (payloadConfig_ == null) {
+ payloadConfig_ = new global::Grpc.Testing.PayloadConfig();
+ }
+ PayloadConfig.MergeFrom(other.PayloadConfig);
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ serverType_ = (global::Grpc.Testing.ServerType) input.ReadEnum();
+ break;
+ }
+ case 18: {
+ if (securityParams_ == null) {
+ securityParams_ = new global::Grpc.Testing.SecurityParams();
+ }
+ input.ReadMessage(securityParams_);
+ break;
+ }
+ case 26: {
+ Host = input.ReadString();
+ break;
+ }
+ case 32: {
+ Port = input.ReadInt32();
+ break;
+ }
+ case 56: {
+ AsyncServerThreads = input.ReadInt32();
+ break;
+ }
+ case 64: {
+ CoreLimit = input.ReadInt32();
+ break;
+ }
+ case 74: {
+ if (payloadConfig_ == null) {
+ payloadConfig_ = new global::Grpc.Testing.PayloadConfig();
+ }
+ input.ReadMessage(payloadConfig_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ServerArgs : pb::IMessage<ServerArgs> {
+ private static readonly pb::MessageParser<ServerArgs> _parser = new pb::MessageParser<ServerArgs>(() => new ServerArgs());
+ public static pb::MessageParser<ServerArgs> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[12]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ServerArgs() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ServerArgs(ServerArgs other) : this() {
+ switch (other.ArgtypeCase) {
+ case ArgtypeOneofCase.Setup:
+ Setup = other.Setup.Clone();
+ break;
+ case ArgtypeOneofCase.Mark:
+ Mark = other.Mark.Clone();
+ break;
+ }
+
+ }
+
+ public ServerArgs Clone() {
+ return new ServerArgs(this);
+ }
+
+ public const int SetupFieldNumber = 1;
+ public global::Grpc.Testing.ServerConfig Setup {
+ get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ServerConfig) argtype_ : null; }
+ set {
+ argtype_ = value;
+ argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Setup;
+ }
+ }
+
+ public const int MarkFieldNumber = 2;
+ public global::Grpc.Testing.Mark Mark {
+ get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; }
+ set {
+ argtype_ = value;
+ argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Mark;
+ }
+ }
+
+ private object argtype_;
+ public enum ArgtypeOneofCase {
+ None = 0,
+ Setup = 1,
+ Mark = 2,
+ }
+ private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None;
+ public ArgtypeOneofCase ArgtypeCase {
+ get { return argtypeCase_; }
+ }
+
+ public void ClearArgtype() {
+ argtypeCase_ = ArgtypeOneofCase.None;
+ argtype_ = null;
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ServerArgs);
+ }
+
+ public bool Equals(ServerArgs other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Setup, other.Setup)) return false;
+ if (!object.Equals(Mark, other.Mark)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode();
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) hash ^= Mark.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Setup);
+ }
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Mark);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Setup);
+ }
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mark);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ServerArgs other) {
+ if (other == null) {
+ return;
+ }
+ switch (other.ArgtypeCase) {
+ case ArgtypeOneofCase.Setup:
+ Setup = other.Setup;
+ break;
+ case ArgtypeOneofCase.Mark:
+ Mark = other.Mark;
+ break;
+ }
+
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ global::Grpc.Testing.ServerConfig subBuilder = new global::Grpc.Testing.ServerConfig();
+ if (argtypeCase_ == ArgtypeOneofCase.Setup) {
+ subBuilder.MergeFrom(Setup);
+ }
+ input.ReadMessage(subBuilder);
+ Setup = subBuilder;
+ break;
+ }
+ case 18: {
+ global::Grpc.Testing.Mark subBuilder = new global::Grpc.Testing.Mark();
+ if (argtypeCase_ == ArgtypeOneofCase.Mark) {
+ subBuilder.MergeFrom(Mark);
+ }
+ input.ReadMessage(subBuilder);
+ Mark = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ServerStatus : pb::IMessage<ServerStatus> {
+ private static readonly pb::MessageParser<ServerStatus> _parser = new pb::MessageParser<ServerStatus>(() => new ServerStatus());
+ public static pb::MessageParser<ServerStatus> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[13]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ServerStatus() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ServerStatus(ServerStatus other) : this() {
+ Stats = other.stats_ != null ? other.Stats.Clone() : null;
+ port_ = other.port_;
+ cores_ = other.cores_;
+ }
+
+ public ServerStatus Clone() {
+ return new ServerStatus(this);
+ }
+
+ public const int StatsFieldNumber = 1;
+ private global::Grpc.Testing.ServerStats stats_;
+ public global::Grpc.Testing.ServerStats Stats {
+ get { return stats_; }
+ set {
+ stats_ = value;
+ }
+ }
+
+ public const int PortFieldNumber = 2;
+ private int port_;
+ public int Port {
+ get { return port_; }
+ set {
+ port_ = value;
+ }
+ }
+
+ public const int CoresFieldNumber = 3;
+ private int cores_;
+ public int Cores {
+ get { return cores_; }
+ set {
+ cores_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ServerStatus);
+ }
+
+ public bool Equals(ServerStatus other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Stats, other.Stats)) return false;
+ if (Port != other.Port) return false;
+ if (Cores != other.Cores) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (stats_ != null) hash ^= Stats.GetHashCode();
+ if (Port != 0) hash ^= Port.GetHashCode();
+ if (Cores != 0) hash ^= Cores.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (stats_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Stats);
+ }
+ if (Port != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(Port);
+ }
+ if (Cores != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(Cores);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (stats_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stats);
+ }
+ if (Port != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port);
+ }
+ if (Cores != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Cores);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ServerStatus other) {
+ if (other == null) {
+ return;
+ }
+ if (other.stats_ != null) {
+ if (stats_ == null) {
+ stats_ = new global::Grpc.Testing.ServerStats();
+ }
+ Stats.MergeFrom(other.Stats);
+ }
+ if (other.Port != 0) {
+ Port = other.Port;
+ }
+ if (other.Cores != 0) {
+ Cores = other.Cores;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (stats_ == null) {
+ stats_ = new global::Grpc.Testing.ServerStats();
+ }
+ input.ReadMessage(stats_);
+ break;
+ }
+ case 16: {
+ Port = input.ReadInt32();
+ break;
+ }
+ case 24: {
+ Cores = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 2b75305731..012de45524 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -38,55 +38,46 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
- </Reference>
<Reference Include="CommandLine">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
+ <Reference Include="BouncyCastle.Crypto">
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Apis.Auth.PlatformServices">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Apis.Core">
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
- <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
- <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
- <Reference Include="nunit.framework">
- <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
- </Reference>
- <Reference Include="System" />
- <Reference Include="System.Interactive.Async">
- <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
- <Reference Include="System.Net" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -104,6 +95,22 @@
<Compile Include="TestGrpc.cs" />
<Compile Include="SslCredentialsTest.cs" />
<Compile Include="Test.cs" />
+ <Compile Include="IClientRunner.cs" />
+ <Compile Include="ClientRunners.cs" />
+ <Compile Include="IServerRunner.cs" />
+ <Compile Include="ServerRunners.cs" />
+ <Compile Include="RunnerClientServerTest.cs" />
+ <Compile Include="Control.cs" />
+ <Compile Include="Payloads.cs" />
+ <Compile Include="Services.cs" />
+ <Compile Include="ServicesGrpc.cs" />
+ <Compile Include="Stats.cs" />
+ <Compile Include="BenchmarkServiceImpl.cs" />
+ <Compile Include="Histogram.cs" />
+ <Compile Include="HistogramTest.cs" />
+ <Compile Include="WorkerServiceImpl.cs" />
+ <Compile Include="QpsWorker.cs" />
+ <Compile Include="WallClockStopwatch.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/Histogram.cs b/src/csharp/Grpc.IntegrationTesting/Histogram.cs
new file mode 100644
index 0000000000..7e7cb2c4de
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Histogram.cs
@@ -0,0 +1,153 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Basic implementation of histogram based on grpc/support/histogram.h.
+ /// </summary>
+ public class Histogram
+ {
+ readonly object myLock = new object();
+ readonly double multiplier;
+ readonly double oneOnLogMultiplier;
+ readonly double maxPossible;
+ readonly uint[] buckets;
+
+ int count;
+ double sum;
+ double sumOfSquares;
+ double min;
+ double max;
+
+ public Histogram(double resolution, double maxPossible)
+ {
+ Grpc.Core.Utils.Preconditions.CheckArgument(resolution > 0);
+ Grpc.Core.Utils.Preconditions.CheckArgument(maxPossible > 0);
+ this.maxPossible = maxPossible;
+ this.multiplier = 1.0 + resolution;
+ this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution);
+ this.buckets = new uint[FindBucket(maxPossible) + 1];
+
+ ResetUnsafe();
+ }
+
+ public void AddObservation(double value)
+ {
+ lock (myLock)
+ {
+ AddObservationUnsafe(value);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets snapshot of stats and reset
+ /// </summary>
+ public HistogramData GetSnapshot(bool reset = false)
+ {
+ lock (myLock)
+ {
+ return GetSnapshotUnsafe(reset);
+ }
+ }
+
+ /// <summary>
+ /// Finds bucket index to which given observation should go.
+ /// </summary>
+ private int FindBucket(double value)
+ {
+ value = Math.Max(value, 1.0);
+ value = Math.Min(value, this.maxPossible);
+ return (int)(Math.Log(value) * oneOnLogMultiplier);
+ }
+
+ private void AddObservationUnsafe(double value)
+ {
+ this.count++;
+ this.sum += value;
+ this.sumOfSquares += value * value;
+ this.min = Math.Min(this.min, value);
+ this.max = Math.Max(this.max, value);
+
+ this.buckets[FindBucket(value)]++;
+ }
+
+ private HistogramData GetSnapshotUnsafe(bool reset)
+ {
+ var data = new HistogramData
+ {
+ Count = count,
+ Sum = sum,
+ SumOfSquares = sumOfSquares,
+ MinSeen = min,
+ MaxSeen = max,
+ Bucket = { buckets }
+ };
+
+ if (reset)
+ {
+ ResetUnsafe();
+ }
+
+ return data;
+ }
+
+ private void ResetUnsafe()
+ {
+ this.count = 0;
+ this.sum = 0;
+ this.sumOfSquares = 0;
+ this.min = double.PositiveInfinity;
+ this.max = double.NegativeInfinity;
+ for (int i = 0; i < this.buckets.Length; i++)
+ {
+ this.buckets[i] = 0;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs b/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs
new file mode 100644
index 0000000000..fa160cbd15
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs
@@ -0,0 +1,104 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class HistogramTest
+ {
+ [Test]
+ public void Simple()
+ {
+ var hist = new Histogram(0.01, 60e9);
+ hist.AddObservation(10000);
+ hist.AddObservation(10000);
+ hist.AddObservation(11000);
+ hist.AddObservation(11000);
+
+ var data = hist.GetSnapshot();
+
+ Assert.AreEqual(4, data.Count);
+ Assert.AreEqual(42000.0, data.Sum, 1e-6);
+ Assert.AreEqual(10000, data.MinSeen);
+ Assert.AreEqual(11000, data.MaxSeen);
+ Assert.AreEqual(2.0*10000*10000 + 2.0*11000*11000, data.SumOfSquares, 1e-6);
+
+ // 1.01^925 < 10000 < 1.01^926
+ Assert.AreEqual(2, data.Bucket[925]);
+ Assert.AreEqual(2, data.Bucket[935]);
+ }
+
+ [Test]
+ public void ExtremeObservations()
+ {
+ var hist = new Histogram(0.01, 60e9);
+ hist.AddObservation(-0.5); // should be in the first bucket
+ hist.AddObservation(1e12); // should be in the last bucket
+
+ var data = hist.GetSnapshot();
+ Assert.AreEqual(1, data.Bucket[0]);
+ Assert.AreEqual(1, data.Bucket[data.Bucket.Count - 1]);
+ }
+
+ [Test]
+ public void Reset()
+ {
+ var hist = new Histogram(0.01, 60e9);
+ hist.AddObservation(10000);
+ hist.AddObservation(11000);
+
+ var data = hist.GetSnapshot(true); // snapshot contains data before reset
+ Assert.AreEqual(2, data.Count);
+ Assert.AreEqual(10000, data.MinSeen);
+ Assert.AreEqual(11000, data.MaxSeen);
+
+ data = hist.GetSnapshot(); // snapshot contains state after reset
+ Assert.AreEqual(0, data.Count);
+ Assert.AreEqual(double.PositiveInfinity, data.MinSeen);
+ Assert.AreEqual(double.NegativeInfinity, data.MaxSeen);
+ Assert.AreEqual(0, data.Sum);
+ Assert.AreEqual(0, data.SumOfSquares);
+ CollectionAssert.AreEqual(new uint[data.Bucket.Count], data.Bucket);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs b/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs
new file mode 100644
index 0000000000..39b94f1e6d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs
@@ -0,0 +1,67 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Abstract client runner.
+ /// </summary>
+ public interface IClientRunner
+ {
+ /// <summary>
+ /// Gets stats snapshot.
+ /// </summary>
+ /// <returns>The stats.</returns>
+ ClientStats GetStats(bool reset);
+
+ /// <summary>
+ /// Asynchronously stops the client.
+ /// </summary>
+ /// <returns>Task that finishes when client has come to a full stop.</returns>
+ Task StopAsync();
+ }
+
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs b/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs
new file mode 100644
index 0000000000..53a62fbf1c
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs
@@ -0,0 +1,72 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Abstract server runner.
+ /// </summary>
+ public interface IServerRunner
+ {
+ /// <summary>
+ /// Port on which the server is listening.
+ /// </summary>
+ int BoundPort { get; }
+
+ /// <summary>
+ /// Gets server stats.
+ /// </summary>
+ /// <returns>The stats.</returns>
+ ServerStats GetStats(bool reset);
+
+ /// <summary>
+ /// Asynchronously stops the server.
+ /// </summary>
+ /// <returns>Task that finishes when server has shutdown.</returns>
+ Task StopAsync();
+ }
+
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Payloads.cs b/src/csharp/Grpc.IntegrationTesting/Payloads.cs
new file mode 100644
index 0000000000..a37dd9a685
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Payloads.cs
@@ -0,0 +1,580 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test/proto/benchmarks/payloads.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Payloads {
+
+ #region Descriptor
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static Payloads() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8SDGdycGMu",
+ "dGVzdGluZyI3ChBCeXRlQnVmZmVyUGFyYW1zEhAKCHJlcV9zaXplGAEgASgF",
+ "EhEKCXJlc3Bfc2l6ZRgCIAEoBSI4ChFTaW1wbGVQcm90b1BhcmFtcxIQCghy",
+ "ZXFfc2l6ZRgBIAEoBRIRCglyZXNwX3NpemUYAiABKAUiFAoSQ29tcGxleFBy",
+ "b3RvUGFyYW1zIsoBCg1QYXlsb2FkQ29uZmlnEjgKDmJ5dGVidWZfcGFyYW1z",
+ "GAEgASgLMh4uZ3JwYy50ZXN0aW5nLkJ5dGVCdWZmZXJQYXJhbXNIABI4Cg1z",
+ "aW1wbGVfcGFyYW1zGAIgASgLMh8uZ3JwYy50ZXN0aW5nLlNpbXBsZVByb3Rv",
+ "UGFyYW1zSAASOgoOY29tcGxleF9wYXJhbXMYAyABKAsyIC5ncnBjLnRlc3Rp",
+ "bmcuQ29tcGxleFByb3RvUGFyYW1zSABCCQoHcGF5bG9hZGIGcHJvdG8z"));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), null, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Messages
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> {
+ private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams());
+ public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[0]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ByteBufferParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ByteBufferParams(ByteBufferParams other) : this() {
+ reqSize_ = other.reqSize_;
+ respSize_ = other.respSize_;
+ }
+
+ public ByteBufferParams Clone() {
+ return new ByteBufferParams(this);
+ }
+
+ public const int ReqSizeFieldNumber = 1;
+ private int reqSize_;
+ public int ReqSize {
+ get { return reqSize_; }
+ set {
+ reqSize_ = value;
+ }
+ }
+
+ public const int RespSizeFieldNumber = 2;
+ private int respSize_;
+ public int RespSize {
+ get { return respSize_; }
+ set {
+ respSize_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ByteBufferParams);
+ }
+
+ public bool Equals(ByteBufferParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ReqSize != other.ReqSize) return false;
+ if (RespSize != other.RespSize) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
+ if (RespSize != 0) hash ^= RespSize.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ReqSize != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(ReqSize);
+ }
+ if (RespSize != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(RespSize);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (ReqSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
+ }
+ if (RespSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ByteBufferParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ReqSize != 0) {
+ ReqSize = other.ReqSize;
+ }
+ if (other.RespSize != 0) {
+ RespSize = other.RespSize;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ ReqSize = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ RespSize = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> {
+ private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams());
+ public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public SimpleProtoParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public SimpleProtoParams(SimpleProtoParams other) : this() {
+ reqSize_ = other.reqSize_;
+ respSize_ = other.respSize_;
+ }
+
+ public SimpleProtoParams Clone() {
+ return new SimpleProtoParams(this);
+ }
+
+ public const int ReqSizeFieldNumber = 1;
+ private int reqSize_;
+ public int ReqSize {
+ get { return reqSize_; }
+ set {
+ reqSize_ = value;
+ }
+ }
+
+ public const int RespSizeFieldNumber = 2;
+ private int respSize_;
+ public int RespSize {
+ get { return respSize_; }
+ set {
+ respSize_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as SimpleProtoParams);
+ }
+
+ public bool Equals(SimpleProtoParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ReqSize != other.ReqSize) return false;
+ if (RespSize != other.RespSize) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
+ if (RespSize != 0) hash ^= RespSize.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ReqSize != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(ReqSize);
+ }
+ if (RespSize != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(RespSize);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (ReqSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
+ }
+ if (RespSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
+ }
+ return size;
+ }
+
+ public void MergeFrom(SimpleProtoParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ReqSize != 0) {
+ ReqSize = other.ReqSize;
+ }
+ if (other.RespSize != 0) {
+ RespSize = other.RespSize;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ ReqSize = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ RespSize = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> {
+ private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams());
+ public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[2]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ComplexProtoParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ComplexProtoParams(ComplexProtoParams other) : this() {
+ }
+
+ public ComplexProtoParams Clone() {
+ return new ComplexProtoParams(this);
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ComplexProtoParams);
+ }
+
+ public bool Equals(ComplexProtoParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ return size;
+ }
+
+ public void MergeFrom(ComplexProtoParams other) {
+ if (other == null) {
+ return;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> {
+ private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig());
+ public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[3]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public PayloadConfig() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public PayloadConfig(PayloadConfig other) : this() {
+ switch (other.PayloadCase) {
+ case PayloadOneofCase.BytebufParams:
+ BytebufParams = other.BytebufParams.Clone();
+ break;
+ case PayloadOneofCase.SimpleParams:
+ SimpleParams = other.SimpleParams.Clone();
+ break;
+ case PayloadOneofCase.ComplexParams:
+ ComplexParams = other.ComplexParams.Clone();
+ break;
+ }
+
+ }
+
+ public PayloadConfig Clone() {
+ return new PayloadConfig(this);
+ }
+
+ public const int BytebufParamsFieldNumber = 1;
+ public global::Grpc.Testing.ByteBufferParams BytebufParams {
+ get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; }
+ set {
+ payload_ = value;
+ payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BytebufParams;
+ }
+ }
+
+ public const int SimpleParamsFieldNumber = 2;
+ public global::Grpc.Testing.SimpleProtoParams SimpleParams {
+ get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; }
+ set {
+ payload_ = value;
+ payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SimpleParams;
+ }
+ }
+
+ public const int ComplexParamsFieldNumber = 3;
+ public global::Grpc.Testing.ComplexProtoParams ComplexParams {
+ get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; }
+ set {
+ payload_ = value;
+ payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ComplexParams;
+ }
+ }
+
+ private object payload_;
+ public enum PayloadOneofCase {
+ None = 0,
+ BytebufParams = 1,
+ SimpleParams = 2,
+ ComplexParams = 3,
+ }
+ private PayloadOneofCase payloadCase_ = PayloadOneofCase.None;
+ public PayloadOneofCase PayloadCase {
+ get { return payloadCase_; }
+ }
+
+ public void ClearPayload() {
+ payloadCase_ = PayloadOneofCase.None;
+ payload_ = null;
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as PayloadConfig);
+ }
+
+ public bool Equals(PayloadConfig other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(BytebufParams, other.BytebufParams)) return false;
+ if (!object.Equals(SimpleParams, other.SimpleParams)) return false;
+ if (!object.Equals(ComplexParams, other.ComplexParams)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode();
+ if (payloadCase_ == PayloadOneofCase.SimpleParams) hash ^= SimpleParams.GetHashCode();
+ if (payloadCase_ == PayloadOneofCase.ComplexParams) hash ^= ComplexParams.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (payloadCase_ == PayloadOneofCase.BytebufParams) {
+ output.WriteRawTag(10);
+ output.WriteMessage(BytebufParams);
+ }
+ if (payloadCase_ == PayloadOneofCase.SimpleParams) {
+ output.WriteRawTag(18);
+ output.WriteMessage(SimpleParams);
+ }
+ if (payloadCase_ == PayloadOneofCase.ComplexParams) {
+ output.WriteRawTag(26);
+ output.WriteMessage(ComplexParams);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (payloadCase_ == PayloadOneofCase.BytebufParams) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytebufParams);
+ }
+ if (payloadCase_ == PayloadOneofCase.SimpleParams) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(SimpleParams);
+ }
+ if (payloadCase_ == PayloadOneofCase.ComplexParams) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ComplexParams);
+ }
+ return size;
+ }
+
+ public void MergeFrom(PayloadConfig other) {
+ if (other == null) {
+ return;
+ }
+ switch (other.PayloadCase) {
+ case PayloadOneofCase.BytebufParams:
+ BytebufParams = other.BytebufParams;
+ break;
+ case PayloadOneofCase.SimpleParams:
+ SimpleParams = other.SimpleParams;
+ break;
+ case PayloadOneofCase.ComplexParams:
+ ComplexParams = other.ComplexParams;
+ break;
+ }
+
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ global::Grpc.Testing.ByteBufferParams subBuilder = new global::Grpc.Testing.ByteBufferParams();
+ if (payloadCase_ == PayloadOneofCase.BytebufParams) {
+ subBuilder.MergeFrom(BytebufParams);
+ }
+ input.ReadMessage(subBuilder);
+ BytebufParams = subBuilder;
+ break;
+ }
+ case 18: {
+ global::Grpc.Testing.SimpleProtoParams subBuilder = new global::Grpc.Testing.SimpleProtoParams();
+ if (payloadCase_ == PayloadOneofCase.SimpleParams) {
+ subBuilder.MergeFrom(SimpleParams);
+ }
+ input.ReadMessage(subBuilder);
+ SimpleParams = subBuilder;
+ break;
+ }
+ case 26: {
+ global::Grpc.Testing.ComplexProtoParams subBuilder = new global::Grpc.Testing.ComplexProtoParams();
+ if (payloadCase_ == PayloadOneofCase.ComplexParams) {
+ subBuilder.MergeFrom(ComplexParams);
+ }
+ input.ReadMessage(subBuilder);
+ ComplexParams = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
new file mode 100644
index 0000000000..686b484345
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
@@ -0,0 +1,108 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+using CommandLine;
+using CommandLine.Text;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class QpsWorker
+ {
+ private class ServerOptions
+ {
+ [Option("driver_port", DefaultValue = 0)]
+ public int DriverPort { get; set; }
+
+ [HelpOption]
+ public string GetUsage()
+ {
+ var help = new HelpText
+ {
+ Heading = "gRPC C# performance testing worker",
+ AddDashesToOption = true
+ };
+ help.AddPreOptionsLine("Usage:");
+ help.AddOptions(this);
+ return help;
+ }
+ }
+
+ ServerOptions options;
+
+ private QpsWorker(ServerOptions options)
+ {
+ this.options = options;
+ }
+
+ public static void Run(string[] args)
+ {
+ var options = new ServerOptions();
+ if (!Parser.Default.ParseArguments(args, options))
+ {
+ Environment.Exit(1);
+ }
+
+ var workerServer = new QpsWorker(options);
+ workerServer.Run();
+ }
+
+ private void Run()
+ {
+ string host = "0.0.0.0";
+ int port = options.DriverPort;
+
+ var server = new Server
+ {
+ Services = { WorkerService.BindService(new WorkerServiceImpl()) },
+ Ports = { new ServerPort(host, options.DriverPort, ServerCredentials.Insecure )}
+ };
+ int boundPort = server.Ports.Single().BoundPort;
+ Console.WriteLine("Running qps worker server on " + string.Format("{0}:{1}", host, boundPort));
+ server.Start();
+
+ server.ShutdownTask.Wait();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
new file mode 100644
index 0000000000..2b51526c88
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
@@ -0,0 +1,117 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Runs performance tests in-process.
+ /// </summary>
+ public class RunnerClientServerTest
+ {
+ const string Host = "localhost";
+ IServerRunner serverRunner;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ var serverConfig = new ServerConfig
+ {
+ ServerType = ServerType.ASYNC_SERVER,
+ Host = Host,
+ PayloadConfig = new PayloadConfig
+ {
+ SimpleParams = new SimpleProtoParams
+ {
+ RespSize = 100
+ }
+ }
+ };
+ serverRunner = ServerRunners.CreateStarted(serverConfig);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ serverRunner.StopAsync().Wait();
+ }
+
+ // Test attribute commented out to prevent running as part of the default test suite.
+ //[Test]
+ //[Category("Performance")]
+ public async Task ClientServerRunner()
+ {
+ var config = new ClientConfig
+ {
+ ServerTargets = { string.Format("{0}:{1}", Host, serverRunner.BoundPort) },
+ RpcType = RpcType.UNARY,
+ LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() },
+ PayloadConfig = new PayloadConfig
+ {
+ SimpleParams = new SimpleProtoParams
+ {
+ ReqSize = 100
+ }
+ },
+ HistogramParams = new HistogramParams
+ {
+ Resolution = 0.01,
+ MaxPossible = 60e9
+ }
+ };
+
+ var runner = ClientRunners.CreateStarted(config);
+
+ System.Console.WriteLine("Warming up");
+ await Task.Delay(3000);
+ runner.GetStats(true); // throw away warm-up data
+
+ System.Console.WriteLine("Benchmarking");
+ await Task.Delay(3000);
+ var stats = runner.GetStats(true);
+ await runner.StopAsync();
+
+ System.Console.WriteLine(stats);
+ System.Console.WriteLine("avg micros/call " + (long) (stats.Latencies.Sum / stats.Latencies.Count / 1000.0));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
new file mode 100644
index 0000000000..e8be7758ce
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
@@ -0,0 +1,124 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Helper methods to start server runners for performance testing.
+ /// </summary>
+ public static class ServerRunners
+ {
+ /// <summary>
+ /// Creates a started server runner.
+ /// </summary>
+ public static IServerRunner CreateStarted(ServerConfig config)
+ {
+ Grpc.Core.Utils.Preconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER);
+ var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure;
+
+ // TODO: qps_driver needs to setup payload properly...
+ int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0;
+ var server = new Server
+ {
+ Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) },
+ Ports = { new ServerPort(config.Host, config.Port, credentials) }
+ };
+
+ server.Start();
+ return new ServerRunnerImpl(server);
+ }
+ }
+
+ /// <summary>
+ /// Server runner.
+ /// </summary>
+ public class ServerRunnerImpl : IServerRunner
+ {
+ readonly Server server;
+ readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+
+ public ServerRunnerImpl(Server server)
+ {
+ this.server = Grpc.Core.Utils.Preconditions.CheckNotNull(server);
+ }
+
+ public int BoundPort
+ {
+ get
+ {
+ return server.Ports.Single().BoundPort;
+ }
+ }
+
+ /// <summary>
+ /// Gets server stats.
+ /// </summary>
+ /// <returns>The stats.</returns>
+ public ServerStats GetStats(bool reset)
+ {
+ var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
+
+ // TODO: populate user time and system time
+ return new ServerStats
+ {
+ TimeElapsed = secondsElapsed,
+ TimeUser = 0,
+ TimeSystem = 0
+ };
+ }
+
+ /// <summary>
+ /// Asynchronously stops the server.
+ /// </summary>
+ /// <returns>Task that finishes when server has shutdown.</returns>
+ public Task StopAsync()
+ {
+ return server.ShutdownAsync();
+ }
+ }
+
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Services.cs b/src/csharp/Grpc.IntegrationTesting/Services.cs
new file mode 100644
index 0000000000..b648da6734
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Services.cs
@@ -0,0 +1,44 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test/proto/benchmarks/services.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Services {
+
+ #region Descriptor
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static Services() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiR0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc2VydmljZXMucHJvdG8SDGdycGMu",
+ "dGVzdGluZxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bxojdGVzdC9wcm90",
+ "by9iZW5jaG1hcmtzL2NvbnRyb2wucHJvdG8yqgEKEEJlbmNobWFya1NlcnZp",
+ "Y2USRgoJVW5hcnlDYWxsEhsuZ3JwYy50ZXN0aW5nLlNpbXBsZVJlcXVlc3Qa",
+ "HC5ncnBjLnRlc3RpbmcuU2ltcGxlUmVzcG9uc2USTgoNU3RyZWFtaW5nQ2Fs",
+ "bBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5n",
+ "LlNpbXBsZVJlc3BvbnNlKAEwATKdAQoNV29ya2VyU2VydmljZRJFCglSdW5T",
+ "ZXJ2ZXISGC5ncnBjLnRlc3RpbmcuU2VydmVyQXJncxoaLmdycGMudGVzdGlu",
+ "Zy5TZXJ2ZXJTdGF0dXMoATABEkUKCVJ1bkNsaWVudBIYLmdycGMudGVzdGlu",
+ "Zy5DbGllbnRBcmdzGhouZ3JwYy50ZXN0aW5nLkNsaWVudFN0YXR1cygBMAFi",
+ "BnByb3RvMw=="));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { global::Grpc.Testing.Messages.Descriptor, global::Grpc.Testing.Control.Descriptor, },
+ new pbr::GeneratedCodeInfo(null, null));
+ }
+ #endregion
+
+ }
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
new file mode 100644
index 0000000000..ce388c6d5c
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -0,0 +1,198 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test/proto/benchmarks/services.proto
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Testing {
+ public static class BenchmarkService
+ {
+ static readonly string __ServiceName = "grpc.testing.BenchmarkService";
+
+ static readonly Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
+ MethodType.Unary,
+ __ServiceName,
+ "UnaryCall",
+ __Marshaller_SimpleRequest,
+ __Marshaller_SimpleResponse);
+
+ static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
+ MethodType.DuplexStreaming,
+ __ServiceName,
+ "StreamingCall",
+ __Marshaller_SimpleRequest,
+ __Marshaller_SimpleResponse);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Services.Descriptor.Services[0]; }
+ }
+
+ // client interface
+ public interface IBenchmarkServiceClient
+ {
+ global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
+ }
+
+ // server-side interface
+ public interface IBenchmarkService
+ {
+ Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
+ }
+
+ // client stub
+ public class BenchmarkServiceClient : ClientBase, IBenchmarkServiceClient
+ {
+ public BenchmarkServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnaryCall, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnaryCall, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_StreamingCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
+ {
+ var call = CreateCall(__Method_StreamingCall, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
+ .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
+ }
+
+ // creates a new client
+ public static BenchmarkServiceClient NewClient(Channel channel)
+ {
+ return new BenchmarkServiceClient(channel);
+ }
+
+ }
+ public static class WorkerService
+ {
+ static readonly string __ServiceName = "grpc.testing.WorkerService";
+
+ static readonly Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>(
+ MethodType.DuplexStreaming,
+ __ServiceName,
+ "RunServer",
+ __Marshaller_ServerArgs,
+ __Marshaller_ServerStatus);
+
+ static readonly Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>(
+ MethodType.DuplexStreaming,
+ __ServiceName,
+ "RunClient",
+ __Marshaller_ClientArgs,
+ __Marshaller_ClientStatus);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Services.Descriptor.Services[1]; }
+ }
+
+ // client interface
+ public interface IWorkerServiceClient
+ {
+ AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
+ AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
+ }
+
+ // server-side interface
+ public interface IWorkerService
+ {
+ Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
+ Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
+ }
+
+ // client stub
+ public class WorkerServiceClient : ClientBase, IWorkerServiceClient
+ {
+ public WorkerServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_RunServer, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
+ {
+ var call = CreateCall(__Method_RunServer, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_RunClient, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
+ {
+ var call = CreateCall(__Method_RunClient, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_RunServer, serviceImpl.RunServer)
+ .AddMethod(__Method_RunClient, serviceImpl.RunClient).Build();
+ }
+
+ // creates a new client
+ public static WorkerServiceClient NewClient(Channel channel)
+ {
+ return new WorkerServiceClient(channel);
+ }
+
+ }
+}
+#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop
index fb99cd4af1..746f2ef5ce 100644
--- a/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop
+++ b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop
@@ -1,7 +1,10 @@
<StyleCopSettings Version="105">
<SourceFileList>
- <SourceFile>Messages.cs</SourceFile>
<SourceFile>Empty.cs</SourceFile>
+ <SourceFile>Control.cs</SourceFile>
+ <SourceFile>Messages.cs</SourceFile>
+ <SourceFile>Payloads.cs</SourceFile>
+ <SourceFile>Stats.cs</SourceFile>
<Settings>
<GlobalSettings>
<BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
diff --git a/src/csharp/Grpc.IntegrationTesting/Stats.cs b/src/csharp/Grpc.IntegrationTesting/Stats.cs
new file mode 100644
index 0000000000..4ae66baffa
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Stats.cs
@@ -0,0 +1,744 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test/proto/benchmarks/stats.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Stats {
+
+ #region Descriptor
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static Stats() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiF0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc3RhdHMucHJvdG8SDGdycGMudGVz",
+ "dGluZyJLCgtTZXJ2ZXJTdGF0cxIUCgx0aW1lX2VsYXBzZWQYASABKAESEQoJ",
+ "dGltZV91c2VyGAIgASgBEhMKC3RpbWVfc3lzdGVtGAMgASgBIjsKD0hpc3Rv",
+ "Z3JhbVBhcmFtcxISCgpyZXNvbHV0aW9uGAEgASgBEhQKDG1heF9wb3NzaWJs",
+ "ZRgCIAEoASJ3Cg1IaXN0b2dyYW1EYXRhEg4KBmJ1Y2tldBgBIAMoDRIQCght",
+ "aW5fc2VlbhgCIAEoARIQCghtYXhfc2VlbhgDIAEoARILCgNzdW0YBCABKAES",
+ "FgoOc3VtX29mX3NxdWFyZXMYBSABKAESDQoFY291bnQYBiABKAEiewoLQ2xp",
+ "ZW50U3RhdHMSLgoJbGF0ZW5jaWVzGAEgASgLMhsuZ3JwYy50ZXN0aW5nLkhp",
+ "c3RvZ3JhbURhdGESFAoMdGltZV9lbGFwc2VkGAIgASgBEhEKCXRpbWVfdXNl",
+ "chgDIAEoARITCgt0aW1lX3N5c3RlbRgEIAEoAWIGcHJvdG8z"));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStats), new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramParams), new[]{ "Resolution", "MaxPossible" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramData), new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStats), new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Messages
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ServerStats : pb::IMessage<ServerStats> {
+ private static readonly pb::MessageParser<ServerStats> _parser = new pb::MessageParser<ServerStats>(() => new ServerStats());
+ public static pb::MessageParser<ServerStats> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[0]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ServerStats() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ServerStats(ServerStats other) : this() {
+ timeElapsed_ = other.timeElapsed_;
+ timeUser_ = other.timeUser_;
+ timeSystem_ = other.timeSystem_;
+ }
+
+ public ServerStats Clone() {
+ return new ServerStats(this);
+ }
+
+ public const int TimeElapsedFieldNumber = 1;
+ private double timeElapsed_;
+ public double TimeElapsed {
+ get { return timeElapsed_; }
+ set {
+ timeElapsed_ = value;
+ }
+ }
+
+ public const int TimeUserFieldNumber = 2;
+ private double timeUser_;
+ public double TimeUser {
+ get { return timeUser_; }
+ set {
+ timeUser_ = value;
+ }
+ }
+
+ public const int TimeSystemFieldNumber = 3;
+ private double timeSystem_;
+ public double TimeSystem {
+ get { return timeSystem_; }
+ set {
+ timeSystem_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ServerStats);
+ }
+
+ public bool Equals(ServerStats other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (TimeElapsed != other.TimeElapsed) return false;
+ if (TimeUser != other.TimeUser) return false;
+ if (TimeSystem != other.TimeSystem) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
+ if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
+ if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (TimeElapsed != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(TimeElapsed);
+ }
+ if (TimeUser != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(TimeUser);
+ }
+ if (TimeSystem != 0D) {
+ output.WriteRawTag(25);
+ output.WriteDouble(TimeSystem);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (TimeElapsed != 0D) {
+ size += 1 + 8;
+ }
+ if (TimeUser != 0D) {
+ size += 1 + 8;
+ }
+ if (TimeSystem != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(ServerStats other) {
+ if (other == null) {
+ return;
+ }
+ if (other.TimeElapsed != 0D) {
+ TimeElapsed = other.TimeElapsed;
+ }
+ if (other.TimeUser != 0D) {
+ TimeUser = other.TimeUser;
+ }
+ if (other.TimeSystem != 0D) {
+ TimeSystem = other.TimeSystem;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ TimeElapsed = input.ReadDouble();
+ break;
+ }
+ case 17: {
+ TimeUser = input.ReadDouble();
+ break;
+ }
+ case 25: {
+ TimeSystem = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class HistogramParams : pb::IMessage<HistogramParams> {
+ private static readonly pb::MessageParser<HistogramParams> _parser = new pb::MessageParser<HistogramParams>(() => new HistogramParams());
+ public static pb::MessageParser<HistogramParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public HistogramParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public HistogramParams(HistogramParams other) : this() {
+ resolution_ = other.resolution_;
+ maxPossible_ = other.maxPossible_;
+ }
+
+ public HistogramParams Clone() {
+ return new HistogramParams(this);
+ }
+
+ public const int ResolutionFieldNumber = 1;
+ private double resolution_;
+ public double Resolution {
+ get { return resolution_; }
+ set {
+ resolution_ = value;
+ }
+ }
+
+ public const int MaxPossibleFieldNumber = 2;
+ private double maxPossible_;
+ public double MaxPossible {
+ get { return maxPossible_; }
+ set {
+ maxPossible_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as HistogramParams);
+ }
+
+ public bool Equals(HistogramParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Resolution != other.Resolution) return false;
+ if (MaxPossible != other.MaxPossible) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Resolution != 0D) hash ^= Resolution.GetHashCode();
+ if (MaxPossible != 0D) hash ^= MaxPossible.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Resolution != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(Resolution);
+ }
+ if (MaxPossible != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(MaxPossible);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Resolution != 0D) {
+ size += 1 + 8;
+ }
+ if (MaxPossible != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(HistogramParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Resolution != 0D) {
+ Resolution = other.Resolution;
+ }
+ if (other.MaxPossible != 0D) {
+ MaxPossible = other.MaxPossible;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ Resolution = input.ReadDouble();
+ break;
+ }
+ case 17: {
+ MaxPossible = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class HistogramData : pb::IMessage<HistogramData> {
+ private static readonly pb::MessageParser<HistogramData> _parser = new pb::MessageParser<HistogramData>(() => new HistogramData());
+ public static pb::MessageParser<HistogramData> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[2]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public HistogramData() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public HistogramData(HistogramData other) : this() {
+ bucket_ = other.bucket_.Clone();
+ minSeen_ = other.minSeen_;
+ maxSeen_ = other.maxSeen_;
+ sum_ = other.sum_;
+ sumOfSquares_ = other.sumOfSquares_;
+ count_ = other.count_;
+ }
+
+ public HistogramData Clone() {
+ return new HistogramData(this);
+ }
+
+ public const int BucketFieldNumber = 1;
+ private static readonly pb::FieldCodec<uint> _repeated_bucket_codec
+ = pb::FieldCodec.ForUInt32(10);
+ private readonly pbc::RepeatedField<uint> bucket_ = new pbc::RepeatedField<uint>();
+ public pbc::RepeatedField<uint> Bucket {
+ get { return bucket_; }
+ }
+
+ public const int MinSeenFieldNumber = 2;
+ private double minSeen_;
+ public double MinSeen {
+ get { return minSeen_; }
+ set {
+ minSeen_ = value;
+ }
+ }
+
+ public const int MaxSeenFieldNumber = 3;
+ private double maxSeen_;
+ public double MaxSeen {
+ get { return maxSeen_; }
+ set {
+ maxSeen_ = value;
+ }
+ }
+
+ public const int SumFieldNumber = 4;
+ private double sum_;
+ public double Sum {
+ get { return sum_; }
+ set {
+ sum_ = value;
+ }
+ }
+
+ public const int SumOfSquaresFieldNumber = 5;
+ private double sumOfSquares_;
+ public double SumOfSquares {
+ get { return sumOfSquares_; }
+ set {
+ sumOfSquares_ = value;
+ }
+ }
+
+ public const int CountFieldNumber = 6;
+ private double count_;
+ public double Count {
+ get { return count_; }
+ set {
+ count_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as HistogramData);
+ }
+
+ public bool Equals(HistogramData other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!bucket_.Equals(other.bucket_)) return false;
+ if (MinSeen != other.MinSeen) return false;
+ if (MaxSeen != other.MaxSeen) return false;
+ if (Sum != other.Sum) return false;
+ if (SumOfSquares != other.SumOfSquares) return false;
+ if (Count != other.Count) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= bucket_.GetHashCode();
+ if (MinSeen != 0D) hash ^= MinSeen.GetHashCode();
+ if (MaxSeen != 0D) hash ^= MaxSeen.GetHashCode();
+ if (Sum != 0D) hash ^= Sum.GetHashCode();
+ if (SumOfSquares != 0D) hash ^= SumOfSquares.GetHashCode();
+ if (Count != 0D) hash ^= Count.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ bucket_.WriteTo(output, _repeated_bucket_codec);
+ if (MinSeen != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(MinSeen);
+ }
+ if (MaxSeen != 0D) {
+ output.WriteRawTag(25);
+ output.WriteDouble(MaxSeen);
+ }
+ if (Sum != 0D) {
+ output.WriteRawTag(33);
+ output.WriteDouble(Sum);
+ }
+ if (SumOfSquares != 0D) {
+ output.WriteRawTag(41);
+ output.WriteDouble(SumOfSquares);
+ }
+ if (Count != 0D) {
+ output.WriteRawTag(49);
+ output.WriteDouble(Count);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ size += bucket_.CalculateSize(_repeated_bucket_codec);
+ if (MinSeen != 0D) {
+ size += 1 + 8;
+ }
+ if (MaxSeen != 0D) {
+ size += 1 + 8;
+ }
+ if (Sum != 0D) {
+ size += 1 + 8;
+ }
+ if (SumOfSquares != 0D) {
+ size += 1 + 8;
+ }
+ if (Count != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(HistogramData other) {
+ if (other == null) {
+ return;
+ }
+ bucket_.Add(other.bucket_);
+ if (other.MinSeen != 0D) {
+ MinSeen = other.MinSeen;
+ }
+ if (other.MaxSeen != 0D) {
+ MaxSeen = other.MaxSeen;
+ }
+ if (other.Sum != 0D) {
+ Sum = other.Sum;
+ }
+ if (other.SumOfSquares != 0D) {
+ SumOfSquares = other.SumOfSquares;
+ }
+ if (other.Count != 0D) {
+ Count = other.Count;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10:
+ case 8: {
+ bucket_.AddEntriesFrom(input, _repeated_bucket_codec);
+ break;
+ }
+ case 17: {
+ MinSeen = input.ReadDouble();
+ break;
+ }
+ case 25: {
+ MaxSeen = input.ReadDouble();
+ break;
+ }
+ case 33: {
+ Sum = input.ReadDouble();
+ break;
+ }
+ case 41: {
+ SumOfSquares = input.ReadDouble();
+ break;
+ }
+ case 49: {
+ Count = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ClientStats : pb::IMessage<ClientStats> {
+ private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats());
+ public static pb::MessageParser<ClientStats> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[3]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ClientStats() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ClientStats(ClientStats other) : this() {
+ Latencies = other.latencies_ != null ? other.Latencies.Clone() : null;
+ timeElapsed_ = other.timeElapsed_;
+ timeUser_ = other.timeUser_;
+ timeSystem_ = other.timeSystem_;
+ }
+
+ public ClientStats Clone() {
+ return new ClientStats(this);
+ }
+
+ public const int LatenciesFieldNumber = 1;
+ private global::Grpc.Testing.HistogramData latencies_;
+ public global::Grpc.Testing.HistogramData Latencies {
+ get { return latencies_; }
+ set {
+ latencies_ = value;
+ }
+ }
+
+ public const int TimeElapsedFieldNumber = 2;
+ private double timeElapsed_;
+ public double TimeElapsed {
+ get { return timeElapsed_; }
+ set {
+ timeElapsed_ = value;
+ }
+ }
+
+ public const int TimeUserFieldNumber = 3;
+ private double timeUser_;
+ public double TimeUser {
+ get { return timeUser_; }
+ set {
+ timeUser_ = value;
+ }
+ }
+
+ public const int TimeSystemFieldNumber = 4;
+ private double timeSystem_;
+ public double TimeSystem {
+ get { return timeSystem_; }
+ set {
+ timeSystem_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ClientStats);
+ }
+
+ public bool Equals(ClientStats other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Latencies, other.Latencies)) return false;
+ if (TimeElapsed != other.TimeElapsed) return false;
+ if (TimeUser != other.TimeUser) return false;
+ if (TimeSystem != other.TimeSystem) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (latencies_ != null) hash ^= Latencies.GetHashCode();
+ if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
+ if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
+ if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (latencies_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Latencies);
+ }
+ if (TimeElapsed != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(TimeElapsed);
+ }
+ if (TimeUser != 0D) {
+ output.WriteRawTag(25);
+ output.WriteDouble(TimeUser);
+ }
+ if (TimeSystem != 0D) {
+ output.WriteRawTag(33);
+ output.WriteDouble(TimeSystem);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (latencies_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Latencies);
+ }
+ if (TimeElapsed != 0D) {
+ size += 1 + 8;
+ }
+ if (TimeUser != 0D) {
+ size += 1 + 8;
+ }
+ if (TimeSystem != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(ClientStats other) {
+ if (other == null) {
+ return;
+ }
+ if (other.latencies_ != null) {
+ if (latencies_ == null) {
+ latencies_ = new global::Grpc.Testing.HistogramData();
+ }
+ Latencies.MergeFrom(other.Latencies);
+ }
+ if (other.TimeElapsed != 0D) {
+ TimeElapsed = other.TimeElapsed;
+ }
+ if (other.TimeUser != 0D) {
+ TimeUser = other.TimeUser;
+ }
+ if (other.TimeSystem != 0D) {
+ TimeSystem = other.TimeSystem;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (latencies_ == null) {
+ latencies_ = new global::Grpc.Testing.HistogramData();
+ }
+ input.ReadMessage(latencies_);
+ break;
+ }
+ case 17: {
+ TimeElapsed = input.ReadDouble();
+ break;
+ }
+ case 25: {
+ TimeUser = input.ReadDouble();
+ break;
+ }
+ case 33: {
+ TimeSystem = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs
new file mode 100644
index 0000000000..e44ae2a5ff
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs
@@ -0,0 +1,78 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Snapshottable wall clock stopwatch.
+ /// </summary>
+ public class WallClockStopwatch
+ {
+ long startTicks;
+
+ public WallClockStopwatch()
+ {
+ this.startTicks = DateTime.UtcNow.Ticks;
+ }
+
+ public TimeSpan GetElapsedSnapshot(bool reset)
+ {
+ var utcNow = DateTime.UtcNow;
+
+ long oldStartTicks;
+ if (reset)
+ {
+ oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks);
+ }
+ else
+ {
+ oldStartTicks = this.startTicks;
+ }
+ return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs
new file mode 100644
index 0000000000..bb2918bf46
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs
@@ -0,0 +1,96 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.IntegrationTesting;
+
+namespace Grpc.Testing
+{
+ /// <summary>
+ /// Implementation of WorkerService server
+ /// </summary>
+ public class WorkerServiceImpl : WorkerService.IWorkerService
+ {
+ public async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context)
+ {
+ Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext());
+ var serverConfig = requestStream.Current.Setup;
+ var runner = ServerRunners.CreateStarted(serverConfig);
+
+ await responseStream.WriteAsync(new ServerStatus
+ {
+ Stats = runner.GetStats(false),
+ Port = runner.BoundPort,
+ Cores = 0, // TODO: set number of cores
+ });
+
+ while (await requestStream.MoveNext())
+ {
+ var reset = requestStream.Current.Mark.Reset;
+ await responseStream.WriteAsync(new ServerStatus
+ {
+ Stats = runner.GetStats(reset)
+ });
+ }
+ await runner.StopAsync();
+ }
+
+ public async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context)
+ {
+ Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext());
+ var clientConfig = requestStream.Current.Setup;
+ var runner = ClientRunners.CreateStarted(clientConfig);
+
+ await responseStream.WriteAsync(new ClientStatus
+ {
+ Stats = runner.GetStats(false)
+ });
+
+ while (await requestStream.MoveNext())
+ {
+ var reset = requestStream.Current.Mark.Reset;
+ await responseStream.WriteAsync(new ClientStatus
+ {
+ Stats = runner.GetStats(reset)
+ });
+ }
+ await runner.StopAsync();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index f19f29c6a2..8ff35e8c0d 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
+# Visual Studio 2012
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
@@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.He
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,72 +41,78 @@ Global
ReleaseSigned|Any CPU = ReleaseSigned|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -112,6 +120,8 @@ Global
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index b864a955a8..45f6b26c66 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,8 +1,8 @@
@rem Builds gRPC NuGet packages
@rem Current package versions
-set VERSION=0.7.1
-set CORE_VERSION=0.11.1
+set VERSION=0.12.0
+set CORE_VERSION=0.12.0
set PROTOBUF_VERSION=3.0.0-alpha4
@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 183931936e..b8705c49d3 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -930,11 +930,12 @@ typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
void *user_data, gpr_int32 is_destroy);
-static void grpcsharp_get_metadata_handler(void *state, const char *service_url,
- grpc_credentials_plugin_metadata_cb cb, void *user_data) {
+static void grpcsharp_get_metadata_handler(
+ void *state, grpc_auth_metadata_context context,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
- interceptor(state, service_url, cb, user_data, 0);
+ interceptor(state, context.service_url, cb, user_data, 0);
}
static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
@@ -949,6 +950,7 @@ GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_cr
plugin.get_metadata = grpcsharp_get_metadata_handler;
plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
plugin.state = (void*)(gpr_intptr)metadata_interceptor;
+ plugin.type = "";
return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
}
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index f879e074aa..92348d1394 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -35,14 +35,14 @@ cd $(dirname $0)
PROTOC=../../bins/opt/protobuf/protoc
PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
EXAMPLES_DIR=Grpc.Examples
-INTEROP_DIR=Grpc.IntegrationTesting
+TESTING_DIR=Grpc.IntegrationTesting
HEALTHCHECK_DIR=Grpc.HealthCheck
$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
-$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
- -I ../.. ../../test/proto/*.proto
+$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
+ -I ../.. ../../test/proto/*.proto ../../test/proto/benchmarks/*.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index e1786ddba7..c306292c04 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -77,6 +77,7 @@ Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
+ gpr_slice_unref(next);
}
return scope.Escape(MakeFastBuffer(
Nan::NewBuffer(result, length).ToLocalChecked()));
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index a98ae85427..1b2ab21dfe 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -234,6 +234,12 @@ class SendMetadataOp : public Op {
class SendMessageOp : public Op {
public:
+ SendMessageOp() { send_message = NULL; }
+ ~SendMessageOp() {
+ if (send_message != NULL) {
+ grpc_byte_buffer_destroy(send_message);
+ }
+ }
Local<Value> GetNodeValue() const {
EscapableHandleScope scope;
return scope.Escape(Nan::True());
@@ -253,7 +259,8 @@ class SendMessageOp : public Op {
out->flags = maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK;
}
}
- out->data.send_message = BufferToByteBuffer(value);
+ send_message = BufferToByteBuffer(value);
+ out->data.send_message = send_message;
PersistentValue *handle = new PersistentValue(value);
resources->handles.push_back(unique_ptr<PersistentValue>(handle));
return true;
@@ -262,6 +269,9 @@ class SendMessageOp : public Op {
std::string GetTypeString() const {
return "send_message";
}
+
+ private:
+ grpc_byte_buffer *send_message;
};
class SendClientCloseOp : public Op {
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index 9c5d9d291b..8cbfb1ebea 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -162,6 +162,7 @@ NAN_METHOD(CallCredentials::CreateFromPlugin) {
plugin.get_metadata = plugin_get_metadata;
plugin.destroy = plugin_destroy_state;
plugin.state = reinterpret_cast<void*>(state);
+ plugin.type = "";
grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
plugin, NULL);
info.GetReturnValue().Set(WrapStruct(creds));
@@ -225,7 +226,7 @@ NAUV_WORK_CB(SendPluginCallback) {
uv_close((uv_handle_t *)async, (uv_close_cb)free);
}
-void plugin_get_metadata(void *state, const char *service_url,
+void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
uv_async_t *async = static_cast<uv_async_t*>(malloc(sizeof(uv_async_t)));
@@ -234,7 +235,7 @@ void plugin_get_metadata(void *state, const char *service_url,
SendPluginCallback);
plugin_callback_data *data = new plugin_callback_data;
data->state = reinterpret_cast<plugin_state*>(state);
- data->service_url = service_url;
+ data->service_url = context.service_url;
data->cb = cb;
data->user_data = user_data;
async->data = data;
diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h
index 1cd8d8dd5d..a9bfe30f94 100644
--- a/src/node/ext/call_credentials.h
+++ b/src/node/ext/call_credentials.h
@@ -84,7 +84,7 @@ typedef struct plugin_callback_data {
void *user_data;
} plugin_callback_data;
-void plugin_get_metadata(void *state, const char *service_url,
+void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data);
diff --git a/src/objective-c/README.md b/src/objective-c/README.md
index c1d25b96f5..30d9aad64c 100644
--- a/src/objective-c/README.md
+++ b/src/objective-c/README.md
@@ -48,8 +48,8 @@ Pod::Spec.new do |s|
s.version = '0.0.1'
s.license = '...'
- s.ios.deployment_target = '6.0'
- s.osx.deployment_target = '10.8'
+ s.ios.deployment_target = '7.1'
+ s.osx.deployment_target = '10.9'
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
# You can run this command manually if you later change your protos and need to regenerate.
@@ -60,7 +60,7 @@ Pod::Spec.new do |s|
ms.source_files = "*.pbobjc.{h,m}"
ms.header_mappings_dir = "."
ms.requires_arc = false
- ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-4"
end
# The --objcgrpc_out plugin generates a pair of .pbrpc.h/.pbrpc.m files for each .proto file with
@@ -69,7 +69,7 @@ Pod::Spec.new do |s|
ss.source_files = "*.pbrpc.{h,m}"
ss.header_mappings_dir = "."
ss.requires_arc = true
- ss.dependency "gRPC", "~> 0.5"
+ ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end
@@ -156,7 +156,7 @@ _protoc_, in which case no system modification nor renaming is necessary.
You need to compile the generated `.pbobjc.*` files (the enums and messages) without ARC support,
and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on
-v0.5+ of the Objective-C gRPC runtime library and v3.0.0-alpha-3+ of the Objective-C Protobuf
+v0.12+ of the Objective-C gRPC runtime library and v3.0.0-alpha-4+ of the Objective-C Protobuf
runtime library.
These libraries need to be integrated into your project as described in their respective Podspec
diff --git a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
index d4f8084cb5..5addf26fc4 100644
--- a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
@@ -3,8 +3,8 @@ Pod::Spec.new do |s|
s.version = "0.0.1"
s.license = "New BSD"
- s.ios.deployment_target = "6.0"
- s.osx.deployment_target = "10.8"
+ s.ios.deployment_target = '7.1'
+ s.osx.deployment_target = '10.9'
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
s.prepare_command = <<-CMD
@@ -22,7 +22,7 @@ Pod::Spec.new do |s|
ss.source_files = "*.pbrpc.{h,m}"
ss.header_mappings_dir = "."
ss.requires_arc = true
- ss.dependency "gRPC", "~> 0.7"
+ ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end
diff --git a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
index 8710753e59..6ecef0593b 100644
--- a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
@@ -3,8 +3,8 @@ Pod::Spec.new do |s|
s.version = "0.0.1"
s.license = "New BSD"
- s.ios.deployment_target = "6.0"
- s.osx.deployment_target = "10.8"
+ s.ios.deployment_target = '7.1'
+ s.osx.deployment_target = '10.9'
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
s.prepare_command = <<-CMD
@@ -18,14 +18,14 @@ Pod::Spec.new do |s|
ms.source_files = "*.pbobjc.{h,m}"
ms.header_mappings_dir = "."
ms.requires_arc = false
- ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-4"
end
s.subspec "Services" do |ss|
ss.source_files = "*.pbrpc.{h,m}"
ss.header_mappings_dir = "."
ss.requires_arc = true
- ss.dependency "gRPC", "~> 0.5"
+ ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index 598f4e7fa1..c4fc5644f2 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -51,4 +51,5 @@ xcodebuild \
-scheme AllTests \
-destination name="iPhone 6" \
test \
- | egrep "$XCODEBUILD_FILTER" -
+ | egrep "$XCODEBUILD_FILTER" \
+ | egrep -v "(GPBDictionary|GPBArray)" -
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index aa4de349ea..7b2627f516 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -216,7 +216,7 @@ class BaseStub
*/
public function _simpleRequest($method,
$argument,
- callable $deserialize,
+ $deserialize,
$metadata = [],
$options = [])
{
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 7972272e2d..db9385e961 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -94,6 +94,10 @@ else
end
$CFLAGS << ' -I' + File.join(grpc_root, 'include')
$LDFLAGS << ' -L' + grpc_lib_dir
+ if grpc_config == 'gcov'
+ $CFLAGS << ' -O0 -fprofile-arcs -ftest-coverage'
+ $LDFLAGS << ' -fprofile-arcs -ftest-coverage -rdynamic'
+ end
raise 'gpr not found' unless have_library('gpr', 'gpr_now')
raise 'grpc not found' unless have_library('grpc', 'grpc_channel_destroy')
end