aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/python_generator.cc22
-rw-r--r--src/compiler/python_generator.h3
-rw-r--r--src/core/ext/census/grpc_filter.c4
-rw-r--r--src/core/ext/client_channel/client_channel.c173
-rw-r--r--src/core/ext/client_channel/parse_address.c5
-rw-r--r--src/core/ext/client_channel/proxy_mapper_registry.c12
-rw-r--r--src/core/ext/client_channel/subchannel.c49
-rw-r--r--src/core/ext/client_channel/subchannel.h18
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c2
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c41
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c2
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c17
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.c65
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.h18
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c60
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c176
-rw-r--r--src/core/lib/channel/channel_stack.c36
-rw-r--r--src/core/lib/channel/channel_stack.h23
-rw-r--r--src/core/lib/channel/compress_filter.c2
-rw-r--r--src/core/lib/channel/connected_channel.c6
-rw-r--r--src/core/lib/channel/deadline_filter.c2
-rw-r--r--src/core/lib/channel/http_client_filter.c2
-rw-r--r--src/core/lib/channel/http_server_filter.c2
-rw-r--r--src/core/lib/channel/message_size_filter.c2
-rw-r--r--src/core/lib/iomgr/error.c460
-rw-r--r--src/core/lib/iomgr/error.h11
-rw-r--r--src/core/lib/iomgr/error_internal.h39
-rw-r--r--src/core/lib/iomgr/pollset_uv.c22
-rw-r--r--src/core/lib/iomgr/port.h4
-rw-r--r--src/core/lib/iomgr/resolve_address_uv.c52
-rw-r--r--src/core/lib/iomgr/tcp_client_uv.c1
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.c416
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix.h134
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_common.c220
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c195
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c49
-rw-r--r--src/core/lib/iomgr/udp_server.c22
-rw-r--r--src/core/lib/iomgr/udp_server.h12
-rw-r--r--src/core/lib/iomgr/wakeup_fd_posix.h2
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c2
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c2
-rw-r--r--src/core/lib/support/arena.c98
-rw-r--r--src/core/lib/support/arena.h54
-rw-r--r--src/core/lib/support/sync.c4
-rw-r--r--src/core/lib/surface/call.c146
-rw-r--r--src/core/lib/surface/channel.c32
-rw-r--r--src/core/lib/surface/channel.h3
-rw-r--r--src/core/lib/surface/lame_client.c4
-rw-r--r--src/core/lib/surface/server.c2
-rw-r--r--src/core/lib/surface/version.c2
-rw-r--r--src/core/lib/transport/error_utils.c22
-rw-r--r--src/core/lib/transport/transport.c12
-rw-r--r--src/core/lib/transport/transport.h6
-rw-r--r--src/core/lib/transport/transport_impl.h5
-rw-r--r--src/cpp/common/channel_arguments.cc14
-rw-r--r--src/cpp/common/channel_filter.h3
-rw-r--r--src/cpp/common/version_cc.cc2
-rw-r--r--src/cpp/server/channel_argument_option.cc78
-rw-r--r--src/cpp/server/server_builder.cc8
-rw-r--r--src/cpp/server/server_cc.cc2
-rw-r--r--src/csharp/Grpc.Auth/project.json4
-rw-r--r--src/csharp/Grpc.Core.Testing/project.json4
-rw-r--r--src/csharp/Grpc.Core.Tests/TestResult.xml41
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rw-r--r--src/csharp/Grpc.Core/project.json2
-rw-r--r--src/csharp/Grpc.HealthCheck/project.json4
-rw-r--r--src/csharp/Grpc.Reflection/project.json4
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat2
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.sh4
-rw-r--r--src/csharp/global.json5
-rw-r--r--src/node/health_check/package.json4
-rw-r--r--src/node/src/server.js2
-rw-r--r--src/node/tools/package.json2
-rw-r--r--src/objective-c/!ProtoCompiler-gRPCPlugin.podspec2
-rw-r--r--src/objective-c/GRPCClient/private/version.h2
-rw-r--r--src/objective-c/tests/InteropTests.m9
-rw-r--r--src/objective-c/tests/InteropTestsLocalCleartext.m6
-rw-r--r--src/objective-c/tests/InteropTestsLocalSSL.m6
-rw-r--r--src/objective-c/tests/InteropTestsRemote.m6
-rw-r--r--src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m8
-rw-r--r--src/php/composer.json2
-rw-r--r--src/php/tests/qps/client.php166
-rw-r--r--src/php/tests/qps/composer.json11
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php127
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Messages.php69
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Payloads.php37
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php34
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php45
-rw-r--r--src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php44
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php78
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php62
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php65
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php84
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php63
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php407
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php164
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php44
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php34
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php28
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php28
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php23
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php56
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php70
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php153
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php93
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php63
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/Mark.php60
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/Payload.php96
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php80
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php26
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php61
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php72
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php44
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php71
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php49
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php65
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php138
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php21
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php291
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php312
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php430
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php48
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php69
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php63
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php305
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php191
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php110
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php33
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php65
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php306
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php129
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php102
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php60
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php171
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php60
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/Void.php23
-rw-r--r--src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php111
-rw-r--r--src/proto/grpc/testing/proxy-service.proto44
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py4
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio_health_checking/grpc_health/v1/health.py3
-rw-r--r--src/python/grpcio_health_checking/grpc_version.py2
-rw-r--r--src/python/grpcio_reflection/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/tests/health_check/_health_servicer_test.py5
-rw-r--r--src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py8
-rw-r--r--src/python/grpcio_tests/tests/interop/_secure_intraop_test.py8
-rw-r--r--src/python/grpcio_tests/tests/interop/methods.py4
-rw-r--r--src/python/grpcio_tests/tests/interop/server.py5
-rw-r--r--src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py9
-rw-r--r--src/python/grpcio_tests/tests/qps/qps_worker.py4
-rw-r--r--src/python/grpcio_tests/tests/qps/worker_server.py8
-rw-r--r--src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py7
-rw-r--r--src/python/grpcio_tests/tests/stress/client.py4
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h3
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rwxr-xr-xsrc/ruby/qps/proxy-worker.rb160
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb17
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb55
-rw-r--r--src/ruby/tools/version.rb2
162 files changed, 7942 insertions, 1137 deletions
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 4841da8da8..242ce06a16 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -101,18 +101,20 @@ class IndentScope {
// TODO(https://github.com/google/protobuf/issues/888):
// Export `ModuleName` from protobuf's
// `src/google/protobuf/compiler/python/python_generator.cc` file.
-grpc::string ModuleName(const grpc::string& filename) {
+grpc::string ModuleName(const grpc::string& filename,
+ const grpc::string& import_prefix) {
grpc::string basename = StripProto(filename);
basename = StringReplace(basename, "-", "_");
basename = StringReplace(basename, "/", ".");
- return basename + "_pb2";
+ return import_prefix + basename + "_pb2";
}
// TODO(https://github.com/google/protobuf/issues/888):
// Export `ModuleAlias` from protobuf's
// `src/google/protobuf/compiler/python/python_generator.cc` file.
-grpc::string ModuleAlias(const grpc::string& filename) {
- grpc::string module_name = ModuleName(filename);
+grpc::string ModuleAlias(const grpc::string& filename,
+ const grpc::string& import_prefix) {
+ grpc::string module_name = ModuleName(filename, import_prefix);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
@@ -189,7 +191,7 @@ bool PrivateGenerator::GetModuleAndMessagePath(const Descriptor* type,
grpc::string generator_file_name = file->name();
grpc::string module;
if (generator_file_name != file_name || generate_in_pb2_grpc) {
- module = ModuleAlias(file_name) + ".";
+ module = ModuleAlias(file_name, config.import_prefix) + ".";
} else {
module = "";
}
@@ -666,8 +668,10 @@ bool PrivateGenerator::PrintPreamble() {
for (int k = 0; k < 2; ++k) {
const Descriptor* type = types[k];
grpc::string type_file_name = type->file()->name();
- grpc::string module_name = ModuleName(type_file_name);
- grpc::string module_alias = ModuleAlias(type_file_name);
+ grpc::string module_name =
+ ModuleName(type_file_name, config.import_prefix);
+ grpc::string module_alias =
+ ModuleAlias(type_file_name, config.import_prefix);
imports_set.insert(std::make_tuple(module_name, module_alias));
}
}
@@ -766,7 +770,9 @@ pair<bool, grpc::string> PrivateGenerator::GetGrpcServices() {
} // namespace
GeneratorConfiguration::GeneratorConfiguration()
- : grpc_package_root("grpc"), beta_package_root("grpc.beta") {}
+ : grpc_package_root("grpc"),
+ beta_package_root("grpc.beta"),
+ import_prefix("") {}
PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
: config_(config) {}
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index 6a95255d40..b91059fad7 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -45,7 +45,10 @@ namespace grpc_python_generator {
struct GeneratorConfiguration {
GeneratorConfiguration();
grpc::string grpc_package_root;
+ // TODO(https://github.com/grpc/grpc/issues/8622): Drop this.
grpc::string beta_package_root;
+ // TODO(https://github.com/google/protobuf/issues/888): Drop this.
+ grpc::string import_prefix;
};
class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index b80d831557..fc29dbd454 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -138,7 +138,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx,
static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@@ -160,7 +160,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx,
static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index bf64f84772..960d00e815 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -71,7 +71,8 @@
*/
typedef enum {
- WAIT_FOR_READY_UNSET,
+ /* zero so it can be default initialized */
+ WAIT_FOR_READY_UNSET = 0,
WAIT_FOR_READY_FALSE,
WAIT_FOR_READY_TRUE
} wait_for_ready_value;
@@ -631,7 +632,8 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
#define CANCELLED_CALL ((grpc_subchannel_call *)1)
typedef enum {
- GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
+ /* zero so that it can be default-initialized */
+ GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING = 0,
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
} subchannel_creation_phase;
@@ -653,13 +655,13 @@ typedef struct client_channel_call_data {
gpr_timespec call_start_time;
gpr_timespec deadline;
method_parameters *method_params;
- grpc_closure read_service_config;
grpc_error *cancel_error;
/** either 0 for no call, 1 for cancelled, or a pointer to a
grpc_subchannel_call */
gpr_atm subchannel_call;
+ gpr_arena *arena;
subchannel_creation_phase creation_phase;
grpc_connected_subchannel *connected_subchannel;
@@ -726,6 +728,47 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
gpr_free(ops);
}
+// Sets calld->method_params.
+// If the method params specify a timeout, populates
+// *per_method_deadline and returns true.
+static bool set_call_method_params_from_service_config_locked(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ gpr_timespec *per_method_deadline) {
+ channel_data *chand = elem->channel_data;
+ call_data *calld = elem->call_data;
+ if (chand->method_params_table != NULL) {
+ calld->method_params = grpc_method_config_table_get(
+ exec_ctx, chand->method_params_table, calld->path);
+ if (calld->method_params != NULL) {
+ method_parameters_ref(calld->method_params);
+ if (gpr_time_cmp(calld->method_params->timeout,
+ gpr_time_0(GPR_TIMESPAN)) != 0) {
+ *per_method_deadline =
+ gpr_time_add(calld->call_start_time, calld->method_params->timeout);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void apply_final_configuration_locked(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem) {
+ /* apply service-config level configuration to the call (now that we're
+ * certain it exists) */
+ call_data *calld = elem->call_data;
+ gpr_timespec per_method_deadline;
+ if (set_call_method_params_from_service_config_locked(exec_ctx, elem,
+ &per_method_deadline)) {
+ // If the deadline from the service config is shorter than the one
+ // from the client API, reset the deadline timer.
+ if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
+ calld->deadline = per_method_deadline;
+ grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
+ }
+ }
+}
+
static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = arg;
@@ -754,9 +797,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
} else {
/* Create call on subchannel. */
grpc_subchannel_call *subchannel_call = NULL;
+ const grpc_connected_subchannel_call_args call_args = {
+ .pollent = calld->pollent,
+ .path = calld->path,
+ .start_time = calld->call_start_time,
+ .deadline = calld->deadline,
+ .arena = calld->arena};
grpc_error *new_error = grpc_connected_subchannel_create_call(
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
- calld->call_start_time, calld->deadline, &subchannel_call);
+ exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL;
@@ -851,6 +899,7 @@ static bool pick_subchannel_locked(
}
GPR_ASSERT(error == GRPC_ERROR_NONE);
if (chand->lb_policy != NULL) {
+ apply_final_configuration_locked(exec_ctx, elem);
grpc_lb_policy *lb_policy = chand->lb_policy;
GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel");
// If the application explicitly set wait_for_ready, use that.
@@ -982,9 +1031,14 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
calld->connected_subchannel != NULL) {
grpc_subchannel_call *subchannel_call = NULL;
+ const grpc_connected_subchannel_call_args call_args = {
+ .pollent = calld->pollent,
+ .path = calld->path,
+ .start_time = calld->call_start_time,
+ .deadline = calld->deadline,
+ .arena = calld->arena};
grpc_error *error = grpc_connected_subchannel_create_call(
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
- calld->call_start_time, calld->deadline, &subchannel_call);
+ exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
@@ -1060,114 +1114,19 @@ static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
GPR_TIMER_END("cc_start_transport_stream_op", 0);
}
-// Sets calld->method_params.
-// If the method params specify a timeout, populates
-// *per_method_deadline and returns true.
-static bool set_call_method_params_from_service_config_locked(
- grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- gpr_timespec *per_method_deadline) {
- channel_data *chand = elem->channel_data;
- call_data *calld = elem->call_data;
- if (chand->method_params_table != NULL) {
- calld->method_params = grpc_method_config_table_get(
- exec_ctx, chand->method_params_table, calld->path);
- if (calld->method_params != NULL) {
- method_parameters_ref(calld->method_params);
- if (gpr_time_cmp(calld->method_params->timeout,
- gpr_time_0(GPR_TIMESPAN)) != 0) {
- *per_method_deadline =
- gpr_time_add(calld->call_start_time, calld->method_params->timeout);
- return true;
- }
- }
- }
- return false;
-}
-
-// Gets data from the service config. Invoked when the resolver returns
-// its initial result.
-static void read_service_config_locked(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- grpc_call_element *elem = arg;
- call_data *calld = elem->call_data;
- // If this is an error, there's no point in looking at the service config.
- if (error == GRPC_ERROR_NONE) {
- gpr_timespec per_method_deadline;
- if (set_call_method_params_from_service_config_locked(
- exec_ctx, elem, &per_method_deadline)) {
- // If the deadline from the service config is shorter than the one
- // from the client API, reset the deadline timer.
- if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
- calld->deadline = per_method_deadline;
- grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
- }
- }
- }
- GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config");
-}
-
-static void initial_read_service_config_locked(grpc_exec_ctx *exec_ctx,
- void *arg,
- grpc_error *error_ignored) {
- grpc_call_element *elem = arg;
- channel_data *chand = elem->channel_data;
- call_data *calld = elem->call_data;
- // If the resolver has already returned results, then we can access
- // the service config parameters immediately. Otherwise, we need to
- // defer that work until the resolver returns an initial result.
- if (chand->lb_policy != NULL) {
- // We already have a resolver result, so check for service config.
- gpr_timespec per_method_deadline;
- if (set_call_method_params_from_service_config_locked(
- exec_ctx, elem, &per_method_deadline)) {
- calld->deadline = gpr_time_min(calld->deadline, per_method_deadline);
- }
- } else {
- // We don't yet have a resolver result, so register a callback to
- // get the service config data once the resolver returns.
- // Take a reference to the call stack to be owned by the callback.
- GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config");
- grpc_closure_init(&calld->read_service_config, read_service_config_locked,
- elem, grpc_combiner_scheduler(chand->combiner, false));
- grpc_closure_list_append(&chand->waiting_for_config_closures,
- &calld->read_service_config, GRPC_ERROR_NONE);
- }
- // Start the deadline timer with the current deadline value. If we
- // do not yet have service config data, then the timer may be reset
- // later.
- grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
- GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,
- "initial_read_service_config");
-}
-
/* Constructor for call_data */
static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_element_args *args) {
- channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
// Initialize data members.
grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
calld->path = grpc_slice_ref_internal(args->path);
calld->call_start_time = args->start_time;
calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
- calld->method_params = NULL;
- calld->cancel_error = GRPC_ERROR_NONE;
- gpr_atm_rel_store(&calld->subchannel_call, 0);
- calld->connected_subchannel = NULL;
- calld->waiting_ops = NULL;
- calld->waiting_ops_count = 0;
- calld->waiting_ops_capacity = 0;
- calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
calld->owning_call = args->call_stack;
- calld->pollent = NULL;
- GRPC_CALL_STACK_REF(calld->owning_call, "initial_read_service_config");
- grpc_closure_sched(
- exec_ctx,
- grpc_closure_init(&calld->read_service_config,
- initial_read_service_config_locked, elem,
- grpc_combiner_scheduler(chand->combiner, false)),
- GRPC_ERROR_NONE);
+ calld->arena = args->arena;
+ grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
return GRPC_ERROR_NONE;
}
@@ -1175,7 +1134,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *and_free_memory) {
+ grpc_closure *then_schedule_closure) {
call_data *calld = elem->call_data;
grpc_deadline_state_destroy(exec_ctx, elem);
grpc_slice_unref_internal(exec_ctx, calld->path);
@@ -1185,6 +1144,8 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_UNREF(calld->cancel_error);
grpc_subchannel_call *call = GET_CALL(calld);
if (call != NULL && call != CANCELLED_CALL) {
+ grpc_subchannel_call_set_cleanup_closure(call, then_schedule_closure);
+ then_schedule_closure = NULL;
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call");
}
GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
@@ -1194,7 +1155,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
"picked");
}
gpr_free(calld->waiting_ops);
- gpr_free(and_free_memory);
+ grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
}
static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/client_channel/parse_address.c b/src/core/ext/client_channel/parse_address.c
index 8ae15fc72b..cd1b2cd80c 100644
--- a/src/core/ext/client_channel/parse_address.c
+++ b/src/core/ext/client_channel/parse_address.c
@@ -128,6 +128,7 @@ int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
GPR_ASSERT(host_end >= host);
char host_without_scope[INET6_ADDRSTRLEN];
size_t host_without_scope_len = (size_t)(host_end - host);
+ uint32_t sin6_scope_id = 0;
strncpy(host_without_scope, host, host_without_scope_len);
host_without_scope[host_without_scope_len] = '\0';
if (inet_pton(AF_INET6, host_without_scope, &in6->sin6_addr) == 0) {
@@ -136,10 +137,12 @@ int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
}
if (gpr_parse_bytes_to_uint32(host_end + 1,
strlen(host) - host_without_scope_len - 1,
- &in6->sin6_scope_id) == 0) {
+ &sin6_scope_id) == 0) {
gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
goto done;
}
+ // Handle "sin6_scope_id" being type "u_long". See grpc issue ##10027.
+ in6->sin6_scope_id = sin6_scope_id;
} else {
if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
diff --git a/src/core/ext/client_channel/proxy_mapper_registry.c b/src/core/ext/client_channel/proxy_mapper_registry.c
index 2c44b9d490..0935ddbdbd 100644
--- a/src/core/ext/client_channel/proxy_mapper_registry.c
+++ b/src/core/ext/client_channel/proxy_mapper_registry.c
@@ -94,6 +94,14 @@ static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) {
grpc_proxy_mapper_destroy(list->list[i]);
}
gpr_free(list->list);
+ // Clean up in case we re-initialze later.
+ // TODO(ctiller): This should ideally live in
+ // grpc_proxy_mapper_registry_init(). However, if we did this there,
+ // then we would do it AFTER we start registering proxy mappers from
+ // third-party plugins, so they'd never show up (and would leak memory).
+ // We probably need some sort of dependency system for plugins to fix
+ // this.
+ memset(list, 0, sizeof(*list));
}
//
@@ -102,9 +110,7 @@ static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) {
static grpc_proxy_mapper_list g_proxy_mapper_list;
-void grpc_proxy_mapper_registry_init() {
- memset(&g_proxy_mapper_list, 0, sizeof(g_proxy_mapper_list));
-}
+void grpc_proxy_mapper_registry_init() {}
void grpc_proxy_mapper_registry_shutdown() {
grpc_proxy_mapper_list_destroy(&g_proxy_mapper_list);
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index 5df0a9060d..ed5029ea9a 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -148,6 +148,7 @@ struct grpc_subchannel {
struct grpc_subchannel_call {
grpc_connected_subchannel *connection;
+ grpc_closure *schedule_closure_after_destroy;
};
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
@@ -340,17 +341,15 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(new_address != NULL);
gpr_free(addr);
addr = new_address;
- if (new_args != NULL) c->args = new_args;
- }
- if (c->args == NULL) {
- static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
- grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
- c->args = grpc_channel_args_copy_and_add_and_remove(
- args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &new_arg,
- 1);
- gpr_free(new_arg.value.string);
}
+ static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
+ grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
gpr_free(addr);
+ c->args = grpc_channel_args_copy_and_add_and_remove(
+ new_args != NULL ? new_args : args->args, keys_to_remove,
+ GPR_ARRAY_SIZE(keys_to_remove), &new_arg, 1);
+ gpr_free(new_arg.value.string);
+ if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args);
c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
&c->root_external_state_watcher;
grpc_closure_init(&c->connected, subchannel_connected, c,
@@ -719,13 +718,22 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) {
grpc_subchannel_call *c = call;
+ GPR_ASSERT(c->schedule_closure_after_destroy != NULL);
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_connected_subchannel *connection = c->connection;
- grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL, c);
+ grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL,
+ c->schedule_closure_after_destroy);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
}
+void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call *call,
+ grpc_closure *closure) {
+ GPR_ASSERT(call->schedule_closure_after_destroy == NULL);
+ GPR_ASSERT(closure != NULL);
+ call->schedule_closure_after_destroy = closure;
+}
+
void grpc_subchannel_call_ref(
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
@@ -761,15 +769,22 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
- grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time,
- gpr_timespec deadline, grpc_subchannel_call **call) {
+ const grpc_connected_subchannel_call_args *args,
+ grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
- *call = gpr_zalloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
+ *call = gpr_arena_alloc(
+ args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
(*call)->connection = con; // Ref is added below.
- grpc_error *error =
- grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call,
- NULL, NULL, path, start_time, deadline, callstk);
+ const grpc_call_element_args call_args = {.call_stack = callstk,
+ .server_transport_data = NULL,
+ .context = NULL,
+ .path = args->path,
+ .start_time = args->start_time,
+ .deadline = args->deadline,
+ .arena = args->arena};
+ grpc_error *error = grpc_call_stack_init(
+ exec_ctx, chanstk, 1, subchannel_call_destroy, *call, &call_args);
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);
@@ -778,7 +793,7 @@ grpc_error *grpc_connected_subchannel_create_call(
return error;
}
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
- grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, pollent);
+ grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 6a70a76467..3e64a2507c 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -37,6 +37,7 @@
#include "src/core/ext/client_channel/connector.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/support/arena.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
@@ -112,10 +113,18 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** construct a subchannel call */
+typedef struct {
+ grpc_polling_entity *pollent;
+ grpc_slice path;
+ gpr_timespec start_time;
+ gpr_timespec deadline;
+ gpr_arena *arena;
+} grpc_connected_subchannel_call_args;
+
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
- grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time,
- gpr_timespec deadline, grpc_subchannel_call **subchannel_call);
+ const grpc_connected_subchannel_call_args *args,
+ grpc_subchannel_call **subchannel_call);
/** process a transport level op */
void grpc_connected_subchannel_process_transport_op(
@@ -154,6 +163,11 @@ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *subchannel_call);
+/** Must be called once per call. Sets the 'then_schedule_closure' argument for
+ call stack destruction. */
+void grpc_subchannel_call_set_cleanup_closure(
+ grpc_subchannel_call *subchannel_call, grpc_closure *closure);
+
grpc_call_stack *grpc_subchannel_call_get_call_stack(
grpc_subchannel_call *subchannel_call);
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index c2750634a5..4ed832671d 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -123,7 +123,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *calld = elem->call_data;
/* TODO(dgq): do something with the data
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index da4c7dc7b2..082078c72f 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -511,6 +511,10 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_error *error) {
if (!t->closed) {
+ if (!grpc_error_has_clear_grpc_status(error)) {
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNAVAILABLE);
+ }
if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) {
if (t->close_transport_on_writes_finished == NULL) {
t->close_transport_on_writes_finished =
@@ -520,10 +524,6 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_error_add_child(t->close_transport_on_writes_finished, error);
return;
}
- if (!grpc_error_has_clear_grpc_status(error)) {
- error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
- GRPC_STATUS_UNAVAILABLE);
- }
t->closed = 1;
connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(error), "close_transport");
@@ -575,7 +575,7 @@ void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) {
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount,
- const void *server_data) {
+ const void *server_data, gpr_arena *arena) {
GPR_TIMER_BEGIN("init_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
@@ -588,8 +588,8 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
gpr_ref_init(&s->active_streams, 1);
GRPC_CHTTP2_STREAM_REF(s, "chttp2");
- grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]);
- grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]);
+ grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena);
+ grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena);
grpc_chttp2_data_parser_init(&s->data_parser);
grpc_slice_buffer_init(&s->flow_controlled_buffer);
s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
@@ -665,16 +665,17 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
GPR_TIMER_END("destroy_stream", 0);
- gpr_free(s->destroy_stream_arg);
+ grpc_closure_sched(exec_ctx, s->destroy_stream_arg, GRPC_ERROR_NONE);
}
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
- grpc_stream *gs, void *and_free_memory) {
+ grpc_stream *gs,
+ grpc_closure *then_schedule_closure) {
GPR_TIMER_BEGIN("destroy_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
- s->destroy_stream_arg = and_free_memory;
+ s->destroy_stream_arg = then_schedule_closure;
grpc_closure_sched(
exec_ctx, grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s,
grpc_combiner_scheduler(t->combiner, false)),
@@ -1629,15 +1630,19 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
s->recv_trailing_metadata_finished != NULL) {
char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string);
- grpc_chttp2_incoming_metadata_buffer_replace_or_add(
- exec_ctx, &s->metadata_buffer[1],
- grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
- grpc_slice_from_copied_string(status_string)));
+ GRPC_LOG_IF_ERROR("add_status",
+ grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ exec_ctx, &s->metadata_buffer[1],
+ grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_GRPC_STATUS,
+ grpc_slice_from_copied_string(status_string))));
if (msg != NULL) {
- grpc_chttp2_incoming_metadata_buffer_replace_or_add(
- exec_ctx, &s->metadata_buffer[1],
- grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_slice_from_copied_string(msg)));
+ GRPC_LOG_IF_ERROR(
+ "add_status_message",
+ grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ exec_ctx, &s->metadata_buffer[1],
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_slice_from_copied_string(msg))));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index f487533c41..9b4b1a7b84 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -91,7 +91,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_ping_parser *p = parser;
while (p->byte != 8 && cur != end) {
- p->opaque_8bytes |= (((uint64_t)*cur) << (8 * p->byte));
+ p->opaque_8bytes |= (((uint64_t)*cur) << (56 - 8 * p->byte));
cur++;
p->byte++;
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 40f5120308..1865b997b7 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -1620,13 +1620,18 @@ void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
grpc_slice slice) {
- /* TODO(ctiller): limit the distance of end from beg, and perform multiple
- steps in the event of a large chunk of data to limit
- stack space usage when no tail call optimization is
- available */
+/* max number of bytes to parse at a time... limits call stack depth on
+ * compilers without TCO */
+#define MAX_PARSE_LENGTH 1024
p->current_slice_refcount = slice.refcount;
- grpc_error *error = p->state(exec_ctx, p, GRPC_SLICE_START_PTR(slice),
- GRPC_SLICE_END_PTR(slice));
+ uint8_t *start = GRPC_SLICE_START_PTR(slice);
+ uint8_t *end = GRPC_SLICE_END_PTR(slice);
+ grpc_error *error = GRPC_ERROR_NONE;
+ while (start != end && error == GRPC_ERROR_NONE) {
+ uint8_t *target = start + GPR_MIN(MAX_PARSE_LENGTH, end - start);
+ error = p->state(exec_ctx, p, start, target);
+ start = target;
+ }
p->current_slice_refcount = NULL;
return error;
}
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.c b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
index c91b019aa0..da0a34d32a 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.c
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
@@ -41,69 +41,48 @@
#include <grpc/support/log.h>
void grpc_chttp2_incoming_metadata_buffer_init(
- grpc_chttp2_incoming_metadata_buffer *buffer) {
- buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+ grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena) {
+ buffer->arena = arena;
+ grpc_metadata_batch_init(&buffer->batch);
+ buffer->batch.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer) {
- size_t i;
- if (!buffer->published) {
- for (i = 0; i < buffer->count; i++) {
- GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
- }
- }
- gpr_free(buffer->elems);
+ grpc_metadata_batch_destroy(exec_ctx, &buffer->batch);
}
-void grpc_chttp2_incoming_metadata_buffer_add(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem) {
- GPR_ASSERT(!buffer->published);
- if (buffer->capacity == buffer->count) {
- buffer->capacity = GPR_MAX(8, 2 * buffer->capacity);
- buffer->elems =
- gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity);
- }
- buffer->elems[buffer->count++].md = elem;
+grpc_error *grpc_chttp2_incoming_metadata_buffer_add(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_mdelem elem) {
buffer->size += GRPC_MDELEM_LENGTH(elem);
+ return grpc_metadata_batch_add_tail(
+ exec_ctx, &buffer->batch,
+ gpr_arena_alloc(buffer->arena, sizeof(grpc_linked_mdelem)), elem);
}
-void grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_mdelem elem) {
- for (size_t i = 0; i < buffer->count; i++) {
- if (grpc_slice_eq(GRPC_MDKEY(buffer->elems[i].md), GRPC_MDKEY(elem))) {
- GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
- buffer->elems[i].md = elem;
- return;
+ for (grpc_linked_mdelem *l = buffer->batch.list.head; l != NULL;
+ l = l->next) {
+ if (grpc_slice_eq(GRPC_MDKEY(l->md), GRPC_MDKEY(elem))) {
+ GRPC_MDELEM_UNREF(exec_ctx, l->md);
+ l->md = elem;
+ return GRPC_ERROR_NONE;
}
}
- grpc_chttp2_incoming_metadata_buffer_add(buffer, elem);
+ return grpc_chttp2_incoming_metadata_buffer_add(exec_ctx, buffer, elem);
}
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) {
- GPR_ASSERT(!buffer->published);
- buffer->deadline = deadline;
+ buffer->batch.deadline = deadline;
}
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_metadata_batch *batch) {
- GPR_ASSERT(!buffer->published);
- buffer->published = 1;
- if (buffer->count > 0) {
- size_t i;
- for (i = 0; i < buffer->count; i++) {
- /* TODO(ctiller): do something better here */
- if (!GRPC_LOG_IF_ERROR("grpc_chttp2_incoming_metadata_buffer_publish",
- grpc_metadata_batch_link_tail(
- exec_ctx, batch, &buffer->elems[i]))) {
- GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
- }
- }
- } else {
- batch->list.head = batch->list.tail = NULL;
- }
- batch->deadline = buffer->deadline;
+ *batch = buffer->batch;
+ grpc_metadata_batch_init(&buffer->batch);
}
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index 1eac6fc150..288c917e65 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -37,28 +37,26 @@
#include "src/core/lib/transport/transport.h"
typedef struct {
- grpc_linked_mdelem *elems;
- size_t count;
- size_t capacity;
- gpr_timespec deadline;
- int published;
+ gpr_arena *arena;
+ grpc_metadata_batch batch;
size_t size; // total size of metadata
} grpc_chttp2_incoming_metadata_buffer;
/** assumes everything initially zeroed */
void grpc_chttp2_incoming_metadata_buffer_init(
- grpc_chttp2_incoming_metadata_buffer *buffer);
+ grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena);
void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer);
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_metadata_batch *batch);
-void grpc_chttp2_incoming_metadata_buffer_add(
- grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem);
-void grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error *grpc_chttp2_incoming_metadata_buffer_add(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
- grpc_mdelem elem);
+ grpc_mdelem elem) GRPC_MUST_USE_RESULT;
+grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
+ grpc_mdelem elem) GRPC_MUST_USE_RESULT;
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline);
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index d26812ad6b..3c56c21599 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -425,7 +425,7 @@ struct grpc_chttp2_stream {
grpc_stream_refcount *refcount;
grpc_closure destroy_stream;
- void *destroy_stream_arg;
+ grpc_closure *destroy_stream_arg;
grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
uint8_t included[STREAM_LIST_COUNT];
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 7ed00522c3..7efc8c63c9 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -381,16 +381,38 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
s->incoming_window_delta +
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]) {
- char *msg;
- gpr_asprintf(&msg,
- "frame of size %d overflows incoming window of %" PRId64,
- t->incoming_frame_size,
- s->incoming_window_delta +
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
- grpc_error *err = GRPC_ERROR_CREATE(msg);
- gpr_free(msg);
- return err;
+ if (incoming_frame_size <=
+ s->incoming_window_delta +
+ t->settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]) {
+ gpr_log(
+ GPR_ERROR,
+ "Incoming frame of size %d exceeds incoming window size of %" PRId64
+ ".\n"
+ "The (un-acked, future) window size would be %" PRId64
+ " which is not exceeded.\n"
+ "This would usually cause a disconnection, but allowing it due to "
+ "broken HTTP2 implementations in the wild.\n"
+ "See (for example) https://github.com/netty/netty/issues/6520.",
+ t->incoming_frame_size,
+ s->incoming_window_delta +
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+ s->incoming_window_delta +
+ t->settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
+ } else {
+ char *msg;
+ gpr_asprintf(&msg,
+ "frame of size %d overflows incoming window of %" PRId64,
+ t->incoming_frame_size,
+ s->incoming_window_delta +
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
+ }
}
GRPC_CHTTP2_FLOW_DEBIT_STREAM_INCOMING_WINDOW_DELTA("parse", t, s,
@@ -526,7 +548,14 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md);
} else {
- grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
+ grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add(
+ exec_ctx, &s->metadata_buffer[0], md);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
+ grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
+ s->seen_error = true;
+ GRPC_MDELEM_UNREF(exec_ctx, md);
+ }
}
}
@@ -576,7 +605,14 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md);
} else {
- grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
+ grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add(
+ exec_ctx, &s->metadata_buffer[1], md);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
+ grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
+ s->seen_error = true;
+ GRPC_MDELEM_UNREF(exec_ctx, md);
+ }
}
GPR_TIMER_END("on_trailing_header", 0);
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 01a03533da..450d9ab23a 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -54,6 +54,7 @@
#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
#define GRPC_HEADER_SIZE_IN_BYTES 5
+#define GRPC_FLUSH_READ_SIZE 4096
#define CRONET_LOG(...) \
do { \
@@ -151,11 +152,17 @@ struct write_state {
struct op_state {
bool state_op_done[OP_NUM_OPS];
bool state_callback_received[OP_NUM_OPS];
+ /* A non-zero gRPC status code has been seen */
bool fail_state;
+ /* Transport is discarding all buffered messages */
bool flush_read;
bool flush_cronet_when_ready;
bool pending_write_for_trailer;
- bool unprocessed_send_message;
+ bool pending_send_message;
+ /* User requested RECV_TRAILING_METADATA */
+ bool pending_recv_trailing_metadata;
+ /* Cronet has not issued a callback of a bidirectional read */
+ bool pending_read_from_cronet;
grpc_error *cancel_error;
/* data structure for storing data coming from server */
struct read_state rs;
@@ -177,6 +184,7 @@ struct op_storage {
};
struct stream_obj {
+ gpr_arena *arena;
struct op_and_state *oas;
grpc_transport_stream_op *curr_op;
grpc_cronet_transport *curr_ct;
@@ -248,11 +256,35 @@ static const char *op_id_string(enum e_op_id i) {
return "UNKNOWN";
}
-static void free_read_buffer(stream_obj *s) {
+static void null_and_maybe_free_read_buffer(stream_obj *s) {
if (s->state.rs.read_buffer &&
s->state.rs.read_buffer != s->state.rs.grpc_header_bytes) {
gpr_free(s->state.rs.read_buffer);
- s->state.rs.read_buffer = NULL;
+ }
+ s->state.rs.read_buffer = NULL;
+}
+
+static void maybe_flush_read(stream_obj *s) {
+ /* To enter flush read state (discarding all the buffered messages in
+ * transport layer), two conditions must be satisfied: 1) non-zero grpc status
+ * has been received, and 2) an op requesting the status code
+ * (RECV_TRAILING_METADATA) is issued by the user. (See
+ * doc/status_ordering.md) */
+ /* Whenever the evaluation of any of the two condition is changed, we check
+ * whether we should enter the flush read state. */
+ if (s->state.pending_recv_trailing_metadata && s->state.fail_state) {
+ if (!s->state.flush_read && !s->state.rs.read_stream_closed) {
+ CRONET_LOG(GPR_DEBUG, "%p: Flush read", s);
+ s->state.flush_read = true;
+ null_and_maybe_free_read_buffer(s);
+ s->state.rs.read_buffer = gpr_malloc(GRPC_FLUSH_READ_SIZE);
+ if (!s->state.pending_read_from_cronet) {
+ CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
+ bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
+ GRPC_FLUSH_READ_SIZE);
+ s->state.pending_read_from_cronet = true;
+ }
+ }
}
}
@@ -279,7 +311,11 @@ static void add_to_storage(struct stream_obj *s, grpc_transport_stream_op *op) {
storage->head = new_op;
storage->num_pending_ops++;
if (op->send_message) {
- s->state.unprocessed_send_message = true;
+ s->state.pending_send_message = true;
+ }
+ if (op->recv_trailing_metadata) {
+ s->state.pending_recv_trailing_metadata = true;
+ maybe_flush_read(s);
}
CRONET_LOG(GPR_DEBUG, "adding new op %p. %d in the queue.", new_op,
storage->num_pending_ops);
@@ -367,7 +403,7 @@ static void on_failed(bidirectional_stream *stream, int net_error) {
gpr_free(s->state.ws.write_buffer);
s->state.ws.write_buffer = NULL;
}
- free_read_buffer(s);
+ null_and_maybe_free_read_buffer(s);
gpr_mu_unlock(&s->mu);
execute_from_storage(s);
}
@@ -390,7 +426,7 @@ static void on_canceled(bidirectional_stream *stream) {
gpr_free(s->state.ws.write_buffer);
s->state.ws.write_buffer = NULL;
}
- free_read_buffer(s);
+ null_and_maybe_free_read_buffer(s);
gpr_mu_unlock(&s->mu);
execute_from_storage(s);
}
@@ -405,7 +441,7 @@ static void on_succeeded(bidirectional_stream *stream) {
bidirectional_stream_destroy(s->cbs);
s->state.state_callback_received[OP_SUCCEEDED] = true;
s->cbs = NULL;
- free_read_buffer(s);
+ null_and_maybe_free_read_buffer(s);
gpr_mu_unlock(&s->mu);
execute_from_storage(s);
}
@@ -451,15 +487,18 @@ static void on_response_headers_received(
gpr_mu_lock(&s->mu);
memset(&s->state.rs.initial_metadata, 0,
sizeof(s->state.rs.initial_metadata));
- grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata);
+ grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata,
+ s->arena);
for (size_t i = 0; i < headers->count; i++) {
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->state.rs.initial_metadata,
- grpc_mdelem_from_slices(
- &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
- headers->headers[i].key)),
- grpc_slice_intern(
- grpc_slice_from_static_string(headers->headers[i].value))));
+ GRPC_LOG_IF_ERROR(
+ "on_response_headers_received",
+ grpc_chttp2_incoming_metadata_buffer_add(
+ &exec_ctx, &s->state.rs.initial_metadata,
+ grpc_mdelem_from_slices(
+ &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
+ headers->headers[i].key)),
+ grpc_slice_intern(grpc_slice_from_static_string(
+ headers->headers[i].value)))));
}
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
@@ -473,6 +512,7 @@ static void on_response_headers_received(
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
s->state.rs.remaining_bytes);
+ s->state.pending_read_from_cronet = true;
}
gpr_mu_unlock(&s->mu);
grpc_exec_ctx_finish(&exec_ctx);
@@ -504,10 +544,13 @@ static void on_read_completed(bidirectional_stream *stream, char *data,
CRONET_LOG(GPR_DEBUG, "R: on_read_completed(%p, %p, %d)", stream, data,
count);
gpr_mu_lock(&s->mu);
+ s->state.pending_read_from_cronet = false;
s->state.state_callback_received[OP_RECV_MESSAGE] = true;
if (count > 0 && s->state.flush_read) {
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
- bidirectional_stream_read(s->cbs, s->state.rs.read_buffer, 4096);
+ bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
+ GRPC_FLUSH_READ_SIZE);
+ s->state.pending_read_from_cronet = true;
gpr_mu_unlock(&s->mu);
} else if (count > 0) {
s->state.rs.received_bytes += count;
@@ -518,16 +561,14 @@ static void on_read_completed(bidirectional_stream *stream, char *data,
bidirectional_stream_read(
s->cbs, s->state.rs.read_buffer + s->state.rs.received_bytes,
s->state.rs.remaining_bytes);
+ s->state.pending_read_from_cronet = true;
gpr_mu_unlock(&s->mu);
} else {
gpr_mu_unlock(&s->mu);
execute_from_storage(s);
}
} else {
- if (s->state.flush_read) {
- gpr_free(s->state.rs.read_buffer);
- s->state.rs.read_buffer = NULL;
- }
+ null_and_maybe_free_read_buffer(s);
s->state.rs.read_stream_closed = true;
gpr_mu_unlock(&s->mu);
execute_from_storage(s);
@@ -549,21 +590,25 @@ static void on_response_trailers_received(
memset(&s->state.rs.trailing_metadata, 0,
sizeof(s->state.rs.trailing_metadata));
s->state.rs.trailing_metadata_valid = false;
- grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata);
+ grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata,
+ s->arena);
for (size_t i = 0; i < trailers->count; i++) {
CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
trailers->headers[i].value);
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->state.rs.trailing_metadata,
- grpc_mdelem_from_slices(
- &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
- trailers->headers[i].key)),
- grpc_slice_intern(
- grpc_slice_from_static_string(trailers->headers[i].value))));
+ GRPC_LOG_IF_ERROR(
+ "on_response_trailers_received",
+ grpc_chttp2_incoming_metadata_buffer_add(
+ &exec_ctx, &s->state.rs.trailing_metadata,
+ grpc_mdelem_from_slices(
+ &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
+ trailers->headers[i].key)),
+ grpc_slice_intern(grpc_slice_from_static_string(
+ trailers->headers[i].value)))));
s->state.rs.trailing_metadata_valid = true;
if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
0 != strcmp(trailers->headers[i].value, "0")) {
s->state.fail_state = true;
+ maybe_flush_read(s);
}
}
s->state.state_callback_received[OP_RECV_TRAILING_METADATA] = true;
@@ -778,7 +823,7 @@ static bool op_can_be_run(grpc_transport_stream_op *curr_op,
else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
result = false;
/* we haven't sent message yet */
- else if (stream_state->unprocessed_send_message &&
+ else if (stream_state->pending_send_message &&
!stream_state->state_op_done[OP_SEND_MESSAGE])
result = false;
/* we haven't got on_write_completed for the send yet */
@@ -900,7 +945,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
} else if (stream_op->send_message &&
op_can_be_run(stream_op, s, &oas->state, OP_SEND_MESSAGE)) {
CRONET_LOG(GPR_DEBUG, "running: %p OP_SEND_MESSAGE", oas);
- stream_state->unprocessed_send_message = false;
+ stream_state->pending_send_message = false;
if (stream_state->state_callback_received[OP_FAILED]) {
result = NO_ACTION_POSSIBLE;
CRONET_LOG(GPR_DEBUG, "Stream is either cancelled or failed.");
@@ -1009,6 +1054,13 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->state_op_done[OP_RECV_MESSAGE] = true;
oas->state.state_op_done[OP_RECV_MESSAGE] = true;
result = ACTION_TAKEN_NO_CALLBACK;
+ } else if (stream_state->flush_read) {
+ CRONET_LOG(GPR_DEBUG, "flush read");
+ grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+ GRPC_ERROR_NONE);
+ stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+ oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+ result = ACTION_TAKEN_NO_CALLBACK;
} else if (stream_state->rs.length_field_received == false) {
if (stream_state->rs.received_bytes == GRPC_HEADER_SIZE_IN_BYTES &&
stream_state->rs.remaining_bytes == 0) {
@@ -1029,6 +1081,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
true; /* Indicates that at least one read request has been made */
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
+ stream_state->pending_read_from_cronet = true;
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
stream_state->rs.remaining_bytes = 0;
@@ -1047,11 +1100,13 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0;
+ stream_state->rs.length_field_received = false;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
+ stream_state->pending_read_from_cronet = true;
result = ACTION_TAKEN_NO_CALLBACK;
}
} else if (stream_state->rs.remaining_bytes == 0) {
@@ -1064,6 +1119,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
true; /* Indicates that at least one read request has been made */
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
+ stream_state->pending_read_from_cronet = true;
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
result = NO_ACTION_POSSIBLE;
@@ -1075,7 +1131,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
uint8_t *dst_p = GRPC_SLICE_START_PTR(read_data_slice);
memcpy(dst_p, stream_state->rs.read_buffer,
(size_t)stream_state->rs.length_field);
- free_read_buffer(s);
+ null_and_maybe_free_read_buffer(s);
grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
grpc_slice_buffer_add(&stream_state->rs.read_slice_buffer,
read_data_slice);
@@ -1096,6 +1152,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
+ stream_state->pending_read_from_cronet = true;
result = ACTION_TAKEN_NO_CALLBACK;
}
} else if (stream_op->recv_trailing_metadata &&
@@ -1153,15 +1210,6 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
make a note */
if (stream_op->recv_message)
stream_state->state_op_done[OP_RECV_MESSAGE_AND_ON_COMPLETE] = true;
- } else if (stream_state->fail_state && !stream_state->flush_read) {
- CRONET_LOG(GPR_DEBUG, "running: %p flush read", oas);
- if (stream_state->rs.read_buffer &&
- stream_state->rs.read_buffer != stream_state->rs.grpc_header_bytes) {
- gpr_free(stream_state->rs.read_buffer);
- stream_state->rs.read_buffer = NULL;
- }
- stream_state->rs.read_buffer = gpr_malloc(4096);
- stream_state->flush_read = true;
} else {
result = NO_ACTION_POSSIBLE;
}
@@ -1174,7 +1222,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount,
- const void *server_data) {
+ const void *server_data, gpr_arena *arena) {
stream_obj *s = (stream_obj *)gs;
memset(&s->storage, 0, sizeof(s->storage));
s->storage.head = NULL;
@@ -1190,10 +1238,13 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
s->state.fail_state = s->state.flush_read = false;
s->state.cancel_error = NULL;
s->state.flush_cronet_when_ready = s->state.pending_write_for_trailer = false;
- s->state.unprocessed_send_message = false;
+ s->state.pending_send_message = false;
+ s->state.pending_recv_trailing_metadata = false;
+ s->state.pending_read_from_cronet = false;
s->curr_gs = gs;
s->curr_ct = (grpc_cronet_transport *)gt;
+ s->arena = arena;
gpr_mu_init(&s->mu);
return 0;
@@ -1209,38 +1260,33 @@ static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_transport_stream_op *op) {
CRONET_LOG(GPR_DEBUG, "perform_stream_op");
- stream_obj *s = (stream_obj *)gs;
- add_to_storage(s, op);
if (op->send_initial_metadata &&
header_has_authority(op->send_initial_metadata->list.head)) {
/* Cronet does not support :authority header field. We cancel the call when
- this field is present in metadata */
- bidirectional_stream_header_array header_array;
- bidirectional_stream_header *header;
- bidirectional_stream cbs;
- CRONET_LOG(GPR_DEBUG,
- ":authority header is provided but not supported;"
- " cancel operations");
- /* Notify application that operation is cancelled by forging trailers */
- header_array.count = 1;
- header_array.capacity = 1;
- header_array.headers = gpr_malloc(sizeof(bidirectional_stream_header));
- header = (bidirectional_stream_header *)header_array.headers;
- header->key = "grpc-status";
- header->value = "1"; /* Return status GRPC_STATUS_CANCELLED */
- cbs.annotation = (void *)s;
- s->state.state_op_done[OP_CANCEL_ERROR] = true;
- on_response_trailers_received(&cbs, &header_array);
- gpr_free(header_array.headers);
- } else {
- execute_from_storage(s);
+ this field is present in metadata */
+ if (op->recv_initial_metadata_ready) {
+ grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
+ GRPC_ERROR_CANCELLED);
+ }
+ if (op->recv_message_ready) {
+ grpc_closure_sched(exec_ctx, op->recv_message_ready,
+ GRPC_ERROR_CANCELLED);
+ }
+ grpc_closure_sched(exec_ctx, op->on_complete, GRPC_ERROR_CANCELLED);
+ return;
}
+ stream_obj *s = (stream_obj *)gs;
+ add_to_storage(s, op);
+ execute_from_storage(s);
}
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
- grpc_stream *gs, void *and_free_memory) {
+ grpc_stream *gs,
+ grpc_closure *then_schedule_closure) {
stream_obj *s = (stream_obj *)gs;
+ null_and_maybe_free_read_buffer(s);
GRPC_ERROR_UNREF(s->state.cancel_error);
+ grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
}
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {}
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 3fb2a60ac7..6d53b0576e 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -166,41 +166,32 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
}
}
-grpc_error *grpc_call_stack_init(
- grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
- int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
- grpc_call_context_element *context, const void *transport_server_data,
- grpc_slice path, gpr_timespec start_time, gpr_timespec deadline,
- grpc_call_stack *call_stack) {
+grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+ grpc_channel_stack *channel_stack,
+ int initial_refs, grpc_iomgr_cb_func destroy,
+ void *destroy_arg,
+ const grpc_call_element_args *elem_args) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
size_t count = channel_stack->count;
grpc_call_element *call_elems;
char *user_data;
size_t i;
- call_stack->count = count;
- GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy,
+ elem_args->call_stack->count = count;
+ GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
destroy_arg, "CALL_STACK");
- call_elems = CALL_ELEMS_FROM_STACK(call_stack);
+ call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack);
user_data = ((char *)call_elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */
grpc_error *first_error = GRPC_ERROR_NONE;
- const grpc_call_element_args args = {
- .start_time = start_time,
- .call_stack = call_stack,
- .server_transport_data = transport_server_data,
- .context = context,
- .path = path,
- .deadline = deadline,
- };
for (i = 0; i < count; i++) {
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
- grpc_error *error =
- call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args);
+ grpc_error *error = call_elems[i].filter->init_call_elem(
+ exec_ctx, &call_elems[i], elem_args);
if (error != GRPC_ERROR_NONE) {
if (first_error == GRPC_ERROR_NONE) {
first_error = error;
@@ -241,15 +232,16 @@ void grpc_call_stack_ignore_set_pollset_or_pollset_set(
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_final_info *final_info,
- void *and_free_memory) {
+ grpc_closure *then_schedule_closure) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
- elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], final_info,
- i == count - 1 ? and_free_memory : NULL);
+ elems[i].filter->destroy_call_elem(
+ exec_ctx, &elems[i], final_info,
+ i == count - 1 ? then_schedule_closure : NULL);
}
}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 6d3340bcbf..80e3603e8d 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -56,6 +56,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/support/arena.h"
#include "src/core/lib/transport/transport.h"
#ifdef __cplusplus
@@ -84,6 +85,7 @@ typedef struct {
grpc_slice path;
gpr_timespec start_time;
gpr_timespec deadline;
+ gpr_arena *arena;
} grpc_call_element_args;
typedef struct {
@@ -139,12 +141,12 @@ typedef struct {
/* Destroy per call data.
The filter does not need to do any chaining.
The bottom filter of a stack will be passed a non-NULL pointer to
- \a and_free_memory that should be passed to gpr_free when destruction
- is complete. \a final_info contains data about the completed call, mainly
- for reporting purposes. */
+ \a then_schedule_closure that should be passed to grpc_closure_sched when
+ destruction is complete. \a final_info contains data about the completed
+ call, mainly for reporting purposes. */
void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *and_free_memory);
+ grpc_closure *then_schedule_closure);
/* sizeof(per channel data) */
size_t sizeof_channel_data;
@@ -236,12 +238,11 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
/* Initialize a call stack given a channel stack. transport_server_data is
expected to be NULL on a client, or an opaque transport owned pointer on the
server. */
-grpc_error *grpc_call_stack_init(
- grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
- int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
- grpc_call_context_element *context, const void *transport_server_data,
- grpc_slice path, gpr_timespec start_time, gpr_timespec deadline,
- grpc_call_stack *call_stack);
+grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+ grpc_channel_stack *channel_stack,
+ int initial_refs, grpc_iomgr_cb_func destroy,
+ void *destroy_arg,
+ const grpc_call_element_args *elem_args);
/* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */
void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -271,7 +272,7 @@ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_final_info *final_info,
- void *and_free_memory);
+ grpc_closure *then_schedule_closure);
/* Ignore set pollset{_set} - used by filters if they don't care about pollsets
* at all. Does nothing. */
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index aa41014a21..02dc479f3a 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -292,7 +292,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 29796f7ca7..42ef7b7806 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -88,7 +88,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data;
int r = grpc_transport_init_stream(
exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- &args->call_stack->refcount, args->server_transport_data);
+ &args->call_stack->refcount, args->server_transport_data, args->arena);
return r == 0 ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("transport stream initialization failed");
}
@@ -105,12 +105,12 @@ static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *and_free_memory) {
+ grpc_closure *then_schedule_closure) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_destroy_stream(exec_ctx, chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- and_free_memory);
+ then_schedule_closure);
}
/* Constructor for channel_data */
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index 5a12d62f1d..34114bbebf 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -256,7 +256,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
// Destructor for call_data. Used for both client and server filters.
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info,
- void* and_free_memory) {
+ grpc_closure* ignored) {
grpc_deadline_state_destroy(exec_ctx, elem);
}
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index c031533dd8..f9d0d689ac 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -412,7 +412,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
}
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index fb70de8e96..bebd3af335 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -358,7 +358,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->read_slice_buffer);
}
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index b424c0d2ac..5ba13fe251 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -200,7 +200,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
// Destructor for call_data.
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info,
- void* ignored) {}
+ grpc_closure* ignored) {}
// Constructor for channel_data.
static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index dbe5b139f9..1127fff756 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -35,6 +35,7 @@
#include <string.h>
+#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@@ -47,46 +48,7 @@
#include "src/core/lib/iomgr/error_internal.h"
#include "src/core/lib/profiling/timers.h"
-
-static void destroy_integer(void *key) {}
-
-static void *copy_integer(void *key) { return key; }
-
-static long compare_integers(void *key1, void *key2) {
- return GPR_ICMP((uintptr_t)key1, (uintptr_t)key2);
-}
-
-static void destroy_string(void *str) { gpr_free(str); }
-
-static void *copy_string(void *str) { return gpr_strdup(str); }
-
-static void destroy_err(void *err) { GRPC_ERROR_UNREF(err); }
-
-static void *copy_err(void *err) { return GRPC_ERROR_REF(err); }
-
-static void destroy_time(void *tm) { gpr_free(tm); }
-
-static gpr_timespec *box_time(gpr_timespec tm) {
- gpr_timespec *out = gpr_malloc(sizeof(*out));
- *out = tm;
- return out;
-}
-
-static void *copy_time(void *tm) { return box_time(*(gpr_timespec *)tm); }
-
-static const gpr_avl_vtable avl_vtable_ints = {destroy_integer, copy_integer,
- compare_integers,
- destroy_integer, copy_integer};
-
-static const gpr_avl_vtable avl_vtable_strs = {destroy_integer, copy_integer,
- compare_integers, destroy_string,
- copy_string};
-
-static const gpr_avl_vtable avl_vtable_times = {
- destroy_integer, copy_integer, compare_integers, destroy_time, copy_time};
-
-static const gpr_avl_vtable avl_vtable_errs = {
- destroy_integer, copy_integer, compare_integers, destroy_err, copy_err};
+#include "src/core/lib/slice/slice_internal.h"
static const char *error_int_name(grpc_error_ints key) {
switch (key) {
@@ -120,6 +82,8 @@ static const char *error_int_name(grpc_error_ints key) {
return "limit";
case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
return "occurred_during_write";
+ case GRPC_ERROR_INT_MAX:
+ GPR_UNREACHABLE_CODE(return "unknown");
}
GPR_UNREACHABLE_CODE(return "unknown");
}
@@ -150,6 +114,8 @@ static const char *error_str_name(grpc_error_strs key) {
return "filename";
case GRPC_ERROR_STR_QUEUED_BUFFERS:
return "queued_buffers";
+ case GRPC_ERROR_STR_MAX:
+ GPR_UNREACHABLE_CODE(return "unknown");
}
GPR_UNREACHABLE_CODE(return "unknown");
}
@@ -158,6 +124,8 @@ static const char *error_time_name(grpc_error_times key) {
switch (key) {
case GRPC_ERROR_TIME_CREATED:
return "created";
+ case GRPC_ERROR_TIME_MAX:
+ GPR_UNREACHABLE_CODE(return "unknown");
}
GPR_UNREACHABLE_CODE(return "unknown");
}
@@ -172,25 +140,51 @@ grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
const char *func) {
if (grpc_error_is_special(err)) return err;
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err,
- err->refs.count, err->refs.count + 1, file, line, func);
- gpr_ref(&err->refs);
+ gpr_atm_no_barrier_load(&err->atomics.refs.count),
+ gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line,
+ func);
+ gpr_ref(&err->atomics.refs);
return err;
}
#else
grpc_error *grpc_error_ref(grpc_error *err) {
if (grpc_error_is_special(err)) return err;
- gpr_ref(&err->refs);
+ gpr_ref(&err->atomics.refs);
return err;
}
#endif
+static void unref_errs(grpc_error *err) {
+ uint8_t slot = err->first_err;
+ while (slot != UINT8_MAX) {
+ grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot);
+ GRPC_ERROR_UNREF(lerr->err);
+ GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
+ : lerr->next != UINT8_MAX);
+ slot = lerr->next;
+ }
+}
+
+static void unref_slice(grpc_slice slice) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_slice_unref_internal(&exec_ctx, slice);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void unref_strs(grpc_error *err) {
+ for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
+ uint8_t slot = err->strs[which];
+ if (slot != UINT8_MAX) {
+ unref_slice(*(grpc_slice *)(err->arena + slot));
+ }
+ }
+}
+
static void error_destroy(grpc_error *err) {
GPR_ASSERT(!grpc_error_is_special(err));
- gpr_avl_unref(err->ints);
- gpr_avl_unref(err->strs);
- gpr_avl_unref(err->errs);
- gpr_avl_unref(err->times);
- gpr_free((void *)gpr_atm_acq_load(&err->error_string));
+ unref_errs(err);
+ unref_strs(err);
+ gpr_free((void *)gpr_atm_acq_load(&err->atomics.error_string));
gpr_free(err);
}
@@ -199,81 +193,209 @@ void grpc_error_unref(grpc_error *err, const char *file, int line,
const char *func) {
if (grpc_error_is_special(err)) return;
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err,
- err->refs.count, err->refs.count - 1, file, line, func);
- if (gpr_unref(&err->refs)) {
+ gpr_atm_no_barrier_load(&err->atomics.refs.count),
+ gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line,
+ func);
+ if (gpr_unref(&err->atomics.refs)) {
error_destroy(err);
}
}
#else
void grpc_error_unref(grpc_error *err) {
if (grpc_error_is_special(err)) return;
- if (gpr_unref(&err->refs)) {
+ if (gpr_unref(&err->atomics.refs)) {
error_destroy(err);
}
}
#endif
+static uint8_t get_placement(grpc_error **err, size_t size) {
+ GPR_ASSERT(*err);
+ uint8_t slots = (uint8_t)(size / sizeof(intptr_t));
+ if ((*err)->arena_size + slots > (*err)->arena_capacity) {
+ (*err)->arena_capacity = (uint8_t)(3 * (*err)->arena_capacity / 2);
+ *err = gpr_realloc(
+ *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
+ }
+ uint8_t placement = (*err)->arena_size;
+ (*err)->arena_size = (uint8_t)((*err)->arena_size + slots);
+ return placement;
+}
+
+static void internal_set_int(grpc_error **err, grpc_error_ints which,
+ intptr_t value) {
+ // GPR_ASSERT((*err)->ints[which] == UINT8_MAX); // TODO, enforce this
+ uint8_t slot = (*err)->ints[which];
+ if (slot == UINT8_MAX) {
+ slot = get_placement(err, sizeof(value));
+ }
+ (*err)->ints[which] = slot;
+ (*err)->arena[slot] = value;
+}
+
+static void internal_set_str(grpc_error **err, grpc_error_strs which,
+ grpc_slice value) {
+ // GPR_ASSERT((*err)->strs[which] == UINT8_MAX); // TODO, enforce this
+ uint8_t slot = (*err)->strs[which];
+ if (slot == UINT8_MAX) {
+ slot = get_placement(err, sizeof(value));
+ } else {
+ unref_slice(*(grpc_slice *)((*err)->arena + slot));
+ }
+ (*err)->strs[which] = slot;
+ memcpy((*err)->arena + slot, &value, sizeof(value));
+}
+
+static void internal_set_time(grpc_error **err, grpc_error_times which,
+ gpr_timespec value) {
+ // GPR_ASSERT((*err)->times[which] == UINT8_MAX); // TODO, enforce this
+ uint8_t slot = (*err)->times[which];
+ if (slot == UINT8_MAX) {
+ slot = get_placement(err, sizeof(value));
+ }
+ (*err)->times[which] = slot;
+ memcpy((*err)->arena + slot, &value, sizeof(value));
+}
+
+static void internal_add_error(grpc_error **err, grpc_error *new) {
+ grpc_linked_error new_last = {new, UINT8_MAX};
+ uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
+ if ((*err)->first_err == UINT8_MAX) {
+ GPR_ASSERT((*err)->last_err == UINT8_MAX);
+ (*err)->last_err = slot;
+ (*err)->first_err = slot;
+ } else {
+ GPR_ASSERT((*err)->last_err != UINT8_MAX);
+ grpc_linked_error *old_last =
+ (grpc_linked_error *)((*err)->arena + (*err)->last_err);
+ old_last->next = slot;
+ (*err)->last_err = slot;
+ }
+ memcpy((*err)->arena + slot, &new_last, sizeof(grpc_linked_error));
+}
+
+#define SLOTS_PER_INT (sizeof(intptr_t) / sizeof(intptr_t))
+#define SLOTS_PER_STR (sizeof(grpc_slice) / sizeof(intptr_t))
+#define SLOTS_PER_TIME (sizeof(gpr_timespec) / sizeof(intptr_t))
+#define SLOTS_PER_LINKED_ERROR (sizeof(grpc_linked_error) / sizeof(intptr_t))
+
+// size of storing one int and two slices and a timespec. For line, desc, file,
+// and time created
+#define DEFAULT_ERROR_CAPACITY \
+ (SLOTS_PER_INT + (SLOTS_PER_STR * 2) + SLOTS_PER_TIME)
+
+// It is very common to include and extra int and string in an error
+#define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
+
grpc_error *grpc_error_create(const char *file, int line, const char *desc,
grpc_error **referencing,
size_t num_referencing) {
GPR_TIMER_BEGIN("grpc_error_create", 0);
- grpc_error *err = gpr_malloc(sizeof(*err));
+ uint8_t initial_arena_capacity = (uint8_t)(
+ DEFAULT_ERROR_CAPACITY +
+ (uint8_t)(num_referencing * SLOTS_PER_LINKED_ERROR) + SURPLUS_CAPACITY);
+ grpc_error *err =
+ gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t));
if (err == NULL) { // TODO(ctiller): make gpr_malloc return NULL
return GRPC_ERROR_OOM;
}
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
#endif
- err->ints = gpr_avl_add(gpr_avl_create(&avl_vtable_ints),
- (void *)(uintptr_t)GRPC_ERROR_INT_FILE_LINE,
- (void *)(uintptr_t)line);
- err->strs = gpr_avl_add(
- gpr_avl_add(gpr_avl_create(&avl_vtable_strs),
- (void *)(uintptr_t)GRPC_ERROR_STR_FILE, gpr_strdup(file)),
- (void *)(uintptr_t)GRPC_ERROR_STR_DESCRIPTION, gpr_strdup(desc));
- err->errs = gpr_avl_create(&avl_vtable_errs);
- err->next_err = 0;
- for (size_t i = 0; i < num_referencing; i++) {
+
+ err->arena_size = 0;
+ err->arena_capacity = initial_arena_capacity;
+ err->first_err = UINT8_MAX;
+ err->last_err = UINT8_MAX;
+
+ memset(err->ints, UINT8_MAX, GRPC_ERROR_INT_MAX);
+ memset(err->strs, UINT8_MAX, GRPC_ERROR_STR_MAX);
+ memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX);
+
+ internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
+ internal_set_str(&err, GRPC_ERROR_STR_FILE,
+ grpc_slice_from_static_string(file));
+ internal_set_str(
+ &err, GRPC_ERROR_STR_DESCRIPTION,
+ grpc_slice_from_copied_buffer(
+ desc,
+ strlen(desc) +
+ 1)); // TODO, pull this up. // TODO(ncteisen), pull this up.
+
+ for (size_t i = 0; i < num_referencing; ++i) {
if (referencing[i] == GRPC_ERROR_NONE) continue;
- err->errs = gpr_avl_add(err->errs, (void *)(err->next_err++),
- GRPC_ERROR_REF(referencing[i]));
- }
- err->times = gpr_avl_add(gpr_avl_create(&avl_vtable_times),
- (void *)(uintptr_t)GRPC_ERROR_TIME_CREATED,
- box_time(gpr_now(GPR_CLOCK_REALTIME)));
- gpr_atm_no_barrier_store(&err->error_string, 0);
- gpr_ref_init(&err->refs, 1);
+ internal_add_error(
+ &err,
+ GRPC_ERROR_REF(
+ referencing[i])); // TODO(ncteisen), change ownership semantics
+ }
+
+ internal_set_time(&err, GRPC_ERROR_TIME_CREATED, gpr_now(GPR_CLOCK_REALTIME));
+
+ gpr_atm_no_barrier_store(&err->atomics.error_string, 0);
+ gpr_ref_init(&err->atomics.refs, 1);
GPR_TIMER_END("grpc_error_create", 0);
return err;
}
+static void ref_strs(grpc_error *err) {
+ for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
+ uint8_t slot = err->strs[i];
+ if (slot != UINT8_MAX) {
+ grpc_slice_ref_internal(*(grpc_slice *)(err->arena + slot));
+ }
+ }
+}
+
+static void ref_errs(grpc_error *err) {
+ uint8_t slot = err->first_err;
+ while (slot != UINT8_MAX) {
+ grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot);
+ GRPC_ERROR_REF(lerr->err);
+ slot = lerr->next;
+ }
+}
+
static grpc_error *copy_error_and_unref(grpc_error *in) {
GPR_TIMER_BEGIN("copy_error_and_unref", 0);
grpc_error *out;
if (grpc_error_is_special(in)) {
- if (in == GRPC_ERROR_NONE)
- out = grpc_error_set_int(GRPC_ERROR_CREATE("no error"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
- else if (in == GRPC_ERROR_OOM)
- out = GRPC_ERROR_CREATE("oom");
- else if (in == GRPC_ERROR_CANCELLED)
- out =
- grpc_error_set_int(GRPC_ERROR_CREATE("cancelled"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED);
- else
- out = GRPC_ERROR_CREATE("unknown");
+ out = GRPC_ERROR_CREATE("unknown");
+ if (in == GRPC_ERROR_NONE) {
+ internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
+ grpc_slice_from_static_string("no error"));
+ internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
+ } else if (in == GRPC_ERROR_OOM) {
+ internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
+ grpc_slice_from_static_string("oom"));
+ } else if (in == GRPC_ERROR_CANCELLED) {
+ internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
+ grpc_slice_from_static_string("cancelled"));
+ internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED);
+ }
+ } else if (gpr_ref_is_unique(&in->atomics.refs)) {
+ out = in;
} else {
- out = gpr_malloc(sizeof(*out));
+ uint8_t new_arena_capacity = in->arena_capacity;
+ // the returned err will be added to, so we ensure this is room to avoid
+ // unneeded allocations.
+ if (in->arena_capacity - in->arena_size < (uint8_t)SLOTS_PER_STR) {
+ new_arena_capacity = (uint8_t)(3 * new_arena_capacity / 2);
+ }
+ out = gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t));
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
#endif
- out->ints = gpr_avl_ref(in->ints);
- out->strs = gpr_avl_ref(in->strs);
- out->errs = gpr_avl_ref(in->errs);
- out->times = gpr_avl_ref(in->times);
- gpr_atm_no_barrier_store(&out->error_string, 0);
- out->next_err = in->next_err;
- gpr_ref_init(&out->refs, 1);
+ // bulk memcpy of the rest of the struct.
+ size_t skip = sizeof(&out->atomics);
+ memcpy((void *)((uintptr_t)out + skip), (void *)((uintptr_t)in + skip),
+ sizeof(*in) + (in->arena_size * sizeof(intptr_t)) - skip);
+ // manually set the atomics and the new capacity
+ gpr_atm_no_barrier_store(&out->atomics.error_string, 0);
+ gpr_ref_init(&out->atomics.refs, 1);
+ out->arena_capacity = new_arena_capacity;
+ ref_strs(out);
+ ref_errs(out);
GRPC_ERROR_UNREF(in);
}
GPR_TIMER_END("copy_error_and_unref", 0);
@@ -284,7 +406,7 @@ grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
intptr_t value) {
GPR_TIMER_BEGIN("grpc_error_set_int", 0);
grpc_error *new = copy_error_and_unref(src);
- new->ints = gpr_avl_add(new->ints, (void *)(uintptr_t)which, (void *)value);
+ internal_set_int(&new, which, value);
GPR_TIMER_END("grpc_error_set_int", 0);
return new;
}
@@ -302,7 +424,6 @@ static special_error_status_map error_status_map[] = {
bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
GPR_TIMER_BEGIN("grpc_error_get_int", 0);
- void *pp;
if (grpc_error_is_special(err)) {
if (which == GRPC_ERROR_INT_GRPC_STATUS) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
@@ -316,8 +437,9 @@ bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
GPR_TIMER_END("grpc_error_get_int", 0);
return false;
}
- if (gpr_avl_maybe_get(err->ints, (void *)(uintptr_t)which, &pp)) {
- if (p != NULL) *p = (intptr_t)pp;
+ uint8_t slot = err->ints[which];
+ if (slot != UINT8_MAX) {
+ if (p != NULL) *p = err->arena[slot];
GPR_TIMER_END("grpc_error_get_int", 0);
return true;
}
@@ -329,8 +451,9 @@ grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value) {
GPR_TIMER_BEGIN("grpc_error_set_str", 0);
grpc_error *new = copy_error_and_unref(src);
- new->strs =
- gpr_avl_add(new->strs, (void *)(uintptr_t)which, gpr_strdup(value));
+ internal_set_str(&new, which,
+ grpc_slice_from_copied_buffer(
+ value, strlen(value) + 1)); // TODO, pull this up.
GPR_TIMER_END("grpc_error_set_str", 0);
return new;
}
@@ -346,13 +469,19 @@ const char *grpc_error_get_str(grpc_error *err, grpc_error_strs which) {
}
return NULL;
}
- return gpr_avl_get(err->strs, (void *)(uintptr_t)which);
+ uint8_t slot = err->strs[which];
+ if (slot != UINT8_MAX) {
+ return (const char *)GRPC_SLICE_START_PTR(
+ *(grpc_slice *)(err->arena + slot));
+ } else {
+ return NULL;
+ }
}
grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) {
GPR_TIMER_BEGIN("grpc_error_add_child", 0);
grpc_error *new = copy_error_and_unref(src);
- new->errs = gpr_avl_add(new->errs, (void *)(new->next_err++), child);
+ internal_add_error(&new, child);
GPR_TIMER_END("grpc_error_add_child", 0);
return new;
}
@@ -372,42 +501,6 @@ typedef struct {
size_t cap_kvs;
} kv_pairs;
-static void append_kv(kv_pairs *kvs, char *key, char *value) {
- if (kvs->num_kvs == kvs->cap_kvs) {
- kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
- kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs);
- }
- kvs->kvs[kvs->num_kvs].key = key;
- kvs->kvs[kvs->num_kvs].value = value;
- kvs->num_kvs++;
-}
-
-static void collect_kvs(gpr_avl_node *node, char *key(void *k),
- char *fmt(void *v), kv_pairs *kvs) {
- if (node == NULL) return;
- append_kv(kvs, key(node->key), fmt(node->value));
- collect_kvs(node->left, key, fmt, kvs);
- collect_kvs(node->right, key, fmt, kvs);
-}
-
-static char *key_int(void *p) {
- return gpr_strdup(error_int_name((grpc_error_ints)(uintptr_t)p));
-}
-
-static char *key_str(void *p) {
- return gpr_strdup(error_str_name((grpc_error_strs)(uintptr_t)p));
-}
-
-static char *key_time(void *p) {
- return gpr_strdup(error_time_name((grpc_error_times)(uintptr_t)p));
-}
-
-static char *fmt_int(void *p) {
- char *s;
- gpr_asprintf(&s, "%" PRIdPTR, (intptr_t)p);
- return s;
-}
-
static void append_chr(char c, char **s, size_t *sz, size_t *cap) {
if (*sz == *cap) {
*cap = GPR_MAX(8, 3 * *cap / 2);
@@ -459,6 +552,40 @@ static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) {
append_chr('"', s, sz, cap);
}
+static void append_kv(kv_pairs *kvs, char *key, char *value) {
+ if (kvs->num_kvs == kvs->cap_kvs) {
+ kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
+ kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs);
+ }
+ kvs->kvs[kvs->num_kvs].key = key;
+ kvs->kvs[kvs->num_kvs].value = value;
+ kvs->num_kvs++;
+}
+
+static char *key_int(grpc_error_ints which) {
+ return gpr_strdup(error_int_name(which));
+}
+
+static char *fmt_int(intptr_t p) {
+ char *s;
+ gpr_asprintf(&s, "%" PRIdPTR, p);
+ return s;
+}
+
+static void collect_ints_kvs(grpc_error *err, kv_pairs *kvs) {
+ for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
+ uint8_t slot = err->ints[which];
+ if (slot != UINT8_MAX) {
+ append_kv(kvs, key_int((grpc_error_ints)which),
+ fmt_int(err->arena[slot]));
+ }
+ }
+}
+
+static char *key_str(grpc_error_strs which) {
+ return gpr_strdup(error_str_name(which));
+}
+
static char *fmt_str(void *p) {
char *s = NULL;
size_t sz = 0;
@@ -468,8 +595,22 @@ static char *fmt_str(void *p) {
return s;
}
-static char *fmt_time(void *p) {
- gpr_timespec tm = *(gpr_timespec *)p;
+static void collect_strs_kvs(grpc_error *err, kv_pairs *kvs) {
+ for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
+ uint8_t slot = err->strs[which];
+ if (slot != UINT8_MAX) {
+ append_kv(
+ kvs, key_str((grpc_error_strs)which),
+ fmt_str(GRPC_SLICE_START_PTR(*(grpc_slice *)(err->arena + slot))));
+ }
+ }
+}
+
+static char *key_time(grpc_error_times which) {
+ return gpr_strdup(error_time_name(which));
+}
+
+static char *fmt_time(gpr_timespec tm) {
char *out;
char *pfx = "!!";
switch (tm.clock_type) {
@@ -490,24 +631,37 @@ static char *fmt_time(void *p) {
return out;
}
-static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap,
- bool *first) {
- if (n == NULL) return;
- add_errs(n->left, s, sz, cap, first);
- if (!*first) append_chr(',', s, sz, cap);
- *first = false;
- const char *e = grpc_error_string(n->value);
- append_str(e, s, sz, cap);
- add_errs(n->right, s, sz, cap, first);
+static void collect_times_kvs(grpc_error *err, kv_pairs *kvs) {
+ for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
+ uint8_t slot = err->times[which];
+ if (slot != UINT8_MAX) {
+ append_kv(kvs, key_time((grpc_error_times)which),
+ fmt_time(*(gpr_timespec *)(err->arena + slot)));
+ }
+ }
+}
+
+static void add_errs(grpc_error *err, char **s, size_t *sz, size_t *cap) {
+ uint8_t slot = err->first_err;
+ bool first = true;
+ while (slot != UINT8_MAX) {
+ grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot);
+ if (!first) append_chr(',', s, sz, cap);
+ first = false;
+ const char *e = grpc_error_string(lerr->err);
+ append_str(e, s, sz, cap);
+ GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
+ : lerr->next != UINT8_MAX);
+ slot = lerr->next;
+ }
}
static char *errs_string(grpc_error *err) {
char *s = NULL;
size_t sz = 0;
size_t cap = 0;
- bool first = true;
append_chr('[', &s, &sz, &cap);
- add_errs(err->errs.root, &s, &sz, &cap, &first);
+ add_errs(err, &s, &sz, &cap);
append_chr(']', &s, &sz, &cap);
append_chr(0, &s, &sz, &cap);
return s;
@@ -546,7 +700,7 @@ const char *grpc_error_string(grpc_error *err) {
if (err == GRPC_ERROR_OOM) return oom_error_string;
if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
- void *p = (void *)gpr_atm_acq_load(&err->error_string);
+ void *p = (void *)gpr_atm_acq_load(&err->atomics.error_string);
if (p != NULL) {
GPR_TIMER_END("grpc_error_string", 0);
return p;
@@ -555,10 +709,10 @@ const char *grpc_error_string(grpc_error *err) {
kv_pairs kvs;
memset(&kvs, 0, sizeof(kvs));
- collect_kvs(err->ints.root, key_int, fmt_int, &kvs);
- collect_kvs(err->strs.root, key_str, fmt_str, &kvs);
- collect_kvs(err->times.root, key_time, fmt_time, &kvs);
- if (!gpr_avl_is_empty(err->errs)) {
+ collect_ints_kvs(err, &kvs);
+ collect_strs_kvs(err, &kvs);
+ collect_times_kvs(err, &kvs);
+ if (err->first_err != UINT8_MAX) {
append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
}
@@ -566,9 +720,9 @@ const char *grpc_error_string(grpc_error *err) {
char *out = finish_kvs(&kvs);
- if (!gpr_atm_rel_cas(&err->error_string, 0, (gpr_atm)out)) {
+ if (!gpr_atm_rel_cas(&err->atomics.error_string, 0, (gpr_atm)out)) {
gpr_free(out);
- out = (char *)gpr_atm_no_barrier_load(&err->error_string);
+ out = (char *)gpr_atm_no_barrier_load(&err->atomics.error_string);
}
GPR_TIMER_END("grpc_error_string", 0);
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 2613512acb..eb953947ae 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -102,6 +102,9 @@ typedef enum {
GRPC_ERROR_INT_LIMIT,
/// chttp2: did the error occur while a write was in progress
GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
+
+ /// Must always be last
+ GRPC_ERROR_INT_MAX,
} grpc_error_ints;
typedef enum {
@@ -129,11 +132,17 @@ typedef enum {
GRPC_ERROR_STR_KEY,
/// value associated with the error
GRPC_ERROR_STR_VALUE,
+
+ /// Must always be last
+ GRPC_ERROR_STR_MAX,
} grpc_error_strs;
typedef enum {
/// timestamp of error creation
GRPC_ERROR_TIME_CREATED,
+
+ /// Must always be last
+ GRPC_ERROR_TIME_MAX,
} grpc_error_times;
/// The following "special" errors can be propagated without allocating memory.
@@ -184,8 +193,6 @@ void grpc_error_unref(grpc_error *err);
grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
intptr_t value) GRPC_MUST_USE_RESULT;
bool grpc_error_get_int(grpc_error *error, grpc_error_ints which, intptr_t *p);
-grpc_error *grpc_error_set_time(grpc_error *src, grpc_error_times which,
- gpr_timespec value) GRPC_MUST_USE_RESULT;
grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value) GRPC_MUST_USE_RESULT;
/// Returns NULL if the specified string is not set.
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
index 1c89ead4ed..7f204df1b2 100644
--- a/src/core/lib/iomgr/error_internal.h
+++ b/src/core/lib/iomgr/error_internal.h
@@ -35,18 +35,39 @@
#define GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H
#include <inttypes.h>
-#include <stdbool.h>
+#include <stdbool.h> // TODO, do we need this?
-#include <grpc/support/avl.h>
+#include <grpc/support/sync.h>
+typedef struct grpc_linked_error grpc_linked_error;
+
+struct grpc_linked_error {
+ grpc_error *err;
+ uint8_t next;
+};
+
+// c core representation of an error. See error.h for high level description of
+// this object.
struct grpc_error {
- gpr_refcount refs;
- gpr_avl ints;
- gpr_avl strs;
- gpr_avl times;
- gpr_avl errs;
- uintptr_t next_err;
- gpr_atm error_string;
+ // All atomics in grpc_error must be stored in this nested struct. The rest of
+ // the object is memcpy-ed in bulk in copy_and_unref.
+ struct atomics {
+ gpr_refcount refs;
+ gpr_atm error_string;
+ } atomics;
+ // These arrays index into dynamic arena at the bottom of the struct.
+ // UINT8_MAX is used as a sentinel value.
+ uint8_t ints[GRPC_ERROR_INT_MAX];
+ uint8_t strs[GRPC_ERROR_STR_MAX];
+ uint8_t times[GRPC_ERROR_TIME_MAX];
+ // The child errors are stored in the arena, but are effectively a linked list
+ // structure, since they are contained withing grpc_linked_error objects.
+ uint8_t first_err;
+ uint8_t last_err;
+ // The arena is dynamically reallocated with a grow factor of 1.5.
+ uint8_t arena_size;
+ uint8_t arena_capacity;
+ intptr_t arena[0];
};
bool grpc_error_is_special(grpc_error *err);
diff --git a/src/core/lib/iomgr/pollset_uv.c b/src/core/lib/iomgr/pollset_uv.c
index af33949c69..a2f81bcd78 100644
--- a/src/core/lib/iomgr/pollset_uv.c
+++ b/src/core/lib/iomgr/pollset_uv.c
@@ -39,6 +39,7 @@
#include <string.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
@@ -61,25 +62,30 @@ gpr_mu grpc_polling_mu;
immediately in the next loop iteration.
Note: In the future, if there is a bug that involves missing wakeups in the
future, try adding a uv_async_t to kick the loop differently */
-uv_timer_t dummy_uv_handle;
+uv_timer_t *dummy_uv_handle;
size_t grpc_pollset_size() { return sizeof(grpc_pollset); }
void dummy_timer_cb(uv_timer_t *handle) {}
+void dummy_handle_close_cb(uv_handle_t *handle) { gpr_free(handle); }
+
void grpc_pollset_global_init(void) {
gpr_mu_init(&grpc_polling_mu);
- uv_timer_init(uv_default_loop(), &dummy_uv_handle);
+ dummy_uv_handle = gpr_malloc(sizeof(uv_timer_t));
+ uv_timer_init(uv_default_loop(), dummy_uv_handle);
grpc_pollset_work_run_loop = 1;
}
-static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; }
-
void grpc_pollset_global_shutdown(void) {
gpr_mu_destroy(&grpc_polling_mu);
- uv_close((uv_handle_t *)&dummy_uv_handle, timer_close_cb);
+ uv_close((uv_handle_t *)dummy_uv_handle, dummy_handle_close_cb);
}
+static void timer_run_cb(uv_timer_t *timer) {}
+
+static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; }
+
void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
*mu = &grpc_polling_mu;
uv_timer_init(uv_default_loop(), &pollset->timer);
@@ -95,7 +101,7 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
uv_run(uv_default_loop(), UV_RUN_NOWAIT);
} else {
// kick the loop once
- uv_timer_start(&dummy_uv_handle, dummy_timer_cb, 0, 0);
+ uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
}
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
}
@@ -111,8 +117,6 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
}
}
-static void timer_run_cb(uv_timer_t *timer) {}
-
grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker_hdl,
gpr_timespec now, gpr_timespec deadline) {
@@ -145,7 +149,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_error *grpc_pollset_kick(grpc_pollset *pollset,
grpc_pollset_worker *specific_worker) {
- uv_timer_start(&dummy_uv_handle, dummy_timer_cb, 0, 0);
+ uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index f1897bb91f..94a454c0b7 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -39,6 +39,7 @@
#if defined(GRPC_UV)
// Do nothing
#elif defined(GPR_MANYLINUX1)
+#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1
@@ -65,6 +66,7 @@
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_LINUX)
+#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1
@@ -90,6 +92,7 @@
#define GRPC_POSIX_SOCKETUTILS
#endif
#elif defined(GPR_APPLE)
+#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_MSG_IOVLEN_TYPE int
@@ -100,6 +103,7 @@
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_FREEBSD)
+#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1
diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c
index 79ff910738..4d715be94c 100644
--- a/src/core/lib/iomgr/resolve_address_uv.c
+++ b/src/core/lib/iomgr/resolve_address_uv.c
@@ -40,6 +40,7 @@
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
@@ -54,8 +55,36 @@ typedef struct request {
grpc_closure *on_done;
grpc_resolved_addresses **addresses;
struct addrinfo *hints;
+ char *host;
+ char *port;
} request;
+static int retry_named_port_failure(int status, request *r,
+ uv_getaddrinfo_cb getaddrinfo_cb) {
+ if (status != 0) {
+ // This loop is copied from resolve_address_posix.c
+ char *svc[][2] = {{"http", "80"}, {"https", "443"}};
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
+ if (strcmp(r->port, svc[i][0]) == 0) {
+ int retry_status;
+ uv_getaddrinfo_t *req = gpr_malloc(sizeof(uv_getaddrinfo_t));
+ req->data = r;
+ retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb,
+ r->host, svc[i][1], r->hints);
+ if (retry_status < 0 || getaddrinfo_cb == NULL) {
+ // The callback will not be called
+ gpr_free(req);
+ }
+ return retry_status;
+ }
+ }
+ }
+ /* If this function calls uv_getaddrinfo, it will return that function's
+ return value. That function only returns numbers <=0, so we can safely
+ return 1 to indicate that we never retried */
+ return 1;
+}
+
static grpc_error *handle_addrinfo_result(int status, struct addrinfo *result,
grpc_resolved_addresses **addresses) {
struct addrinfo *resp;
@@ -97,13 +126,21 @@ static void getaddrinfo_callback(uv_getaddrinfo_t *req, int status,
request *r = (request *)req->data;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *error;
+ int retry_status;
+
+ gpr_free(req);
+ retry_status = retry_named_port_failure(status, r, getaddrinfo_callback);
+ if (retry_status == 0) {
+ // The request is being retried. Nothing should be done here
+ return;
+ }
+ /* Either no retry was attempted, or the retry failed. Either way, the
+ original error probably has more interesting information */
error = handle_addrinfo_result(status, res, r->addresses);
grpc_closure_sched(&exec_ctx, r->on_done, error);
grpc_exec_ctx_finish(&exec_ctx);
-
gpr_free(r->hints);
gpr_free(r);
- gpr_free(req);
uv_freeaddrinfo(res);
}
@@ -143,6 +180,7 @@ static grpc_error *blocking_resolve_address_impl(
uv_getaddrinfo_t req;
int s;
grpc_error *err;
+ int retry_status;
req.addrinfo = NULL;
@@ -158,6 +196,12 @@ static grpc_error *blocking_resolve_address_impl(
hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */
s = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints);
+ request r = {
+ .addresses = addresses, .hints = &hints, .host = host, .port = port};
+ retry_status = retry_named_port_failure(s, &r, NULL);
+ if (retry_status <= 0) {
+ s = retry_status;
+ }
err = handle_addrinfo_result(s, req.addrinfo, addresses);
done:
@@ -200,6 +244,8 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
r = gpr_malloc(sizeof(request));
r->on_done = on_done;
r->addresses = addrs;
+ r->host = host;
+ r->port = port;
req = gpr_malloc(sizeof(uv_getaddrinfo_t));
req->data = r;
@@ -222,6 +268,8 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
gpr_free(r);
gpr_free(req);
gpr_free(hints);
+ gpr_free(host);
+ gpr_free(port);
}
}
diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c
index ae66577caf..618483d9cb 100644
--- a/src/core/lib/iomgr/tcp_client_uv.c
+++ b/src/core/lib/iomgr/tcp_client_uv.c
@@ -76,7 +76,6 @@ static void uv_tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp,
const char *str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
connect->addr_name, str);
- grpc_error_free_string(str);
}
if (error == GRPC_ERROR_NONE) {
/* error == NONE implies that the timer ran out, and wasn't cancelled. If
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 5f286a6723..e242631fc0 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -44,11 +44,8 @@
#include <errno.h>
#include <fcntl.h>
-#include <ifaddrs.h>
-#include <limits.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
-#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -67,82 +64,10 @@
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/support/string.h"
-#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 grpc_tcp_listener grpc_tcp_listener;
-struct grpc_tcp_listener {
- int fd;
- grpc_fd *emfd;
- grpc_tcp_server *server;
- grpc_resolved_address addr;
- int port;
- unsigned port_index;
- unsigned fd_index;
- grpc_closure read_closure;
- grpc_closure destroyed_closure;
- struct grpc_tcp_listener *next;
- /* sibling is a linked list of all listeners for a given port. add_port and
- clone_port place all new listeners in the same sibling list. A member of
- the 'sibling' list is also a member of the 'next' list. The head of each
- sibling list has is_sibling==0, and subsequent members of sibling lists
- have is_sibling==1. is_sibling allows separate sibling lists to be
- identified while iterating through 'next'. */
- struct grpc_tcp_listener *sibling;
- int is_sibling;
-};
-
-/* the overall server */
-struct grpc_tcp_server {
- gpr_refcount refs;
- /* Called whenever accept() succeeds on a server port. */
- grpc_tcp_server_cb on_accept_cb;
- void *on_accept_cb_arg;
-
- gpr_mu mu;
-
- /* active port count: how many ports are actually still listening */
- size_t active_ports;
- /* destroyed port count: how many ports are completely destroyed */
- size_t destroyed_ports;
-
- /* is this server shutting down? */
- bool shutdown;
- /* have listeners been shutdown? */
- bool shutdown_listeners;
- /* use SO_REUSEPORT */
- bool so_reuseport;
- /* expand wildcard addresses to a list of all local addresses */
- bool expand_wildcard_addrs;
-
- /* linked list of server ports */
- grpc_tcp_listener *head;
- grpc_tcp_listener *tail;
- unsigned nports;
-
- /* List of closures passed to shutdown_starting_add(). */
- grpc_closure_list shutdown_starting;
-
- /* shutdown callback */
- grpc_closure *shutdown_complete;
-
- /* all pollsets interested in new connections */
- grpc_pollset **pollsets;
- /* number of pollsets in the pollsets array */
- size_t pollset_count;
-
- /* next pollset to assign a channel to */
- gpr_atm next_pollset_to_assign;
-
- grpc_resource_quota *resource_quota;
-};
-
static gpr_once check_init = GPR_ONCE_INIT;
static bool has_so_reuseport = false;
@@ -301,99 +226,6 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
}
}
-/* get max listen queue size on linux */
-static void init_max_accept_queue_size(void) {
- int n = SOMAXCONN;
- char buf[64];
- FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
- if (fp == NULL) {
- /* 2.4 kernel. */
- s_max_accept_queue_size = SOMAXCONN;
- return;
- }
- if (fgets(buf, sizeof buf, fp)) {
- char *end;
- long i = strtol(buf, &end, 10);
- if (i > 0 && i <= INT_MAX && end && *end == 0) {
- n = (int)i;
- }
- }
- fclose(fp);
- s_max_accept_queue_size = n;
-
- if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
- gpr_log(GPR_INFO,
- "Suspiciously small accept queue (%d) will probably lead to "
- "connection drops",
- s_max_accept_queue_size);
- }
-}
-
-static int get_max_accept_queue_size(void) {
- gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
- return s_max_accept_queue_size;
-}
-
-/* Prepare a recently-created socket for listening. */
-static grpc_error *prepare_socket(int fd, const grpc_resolved_address *addr,
- bool so_reuseport, int *port) {
- grpc_resolved_address sockname_temp;
- grpc_error *err = GRPC_ERROR_NONE;
-
- GPR_ASSERT(fd >= 0);
-
- if (so_reuseport && !grpc_is_unix_socket(addr)) {
- err = grpc_set_socket_reuse_port(fd, 1);
- if (err != GRPC_ERROR_NONE) goto error;
- }
-
- err = grpc_set_socket_nonblocking(fd, 1);
- if (err != GRPC_ERROR_NONE) goto error;
- err = grpc_set_socket_cloexec(fd, 1);
- if (err != GRPC_ERROR_NONE) goto error;
- if (!grpc_is_unix_socket(addr)) {
- err = grpc_set_socket_low_latency(fd, 1);
- if (err != GRPC_ERROR_NONE) goto error;
- err = grpc_set_socket_reuse_addr(fd, 1);
- if (err != GRPC_ERROR_NONE) goto error;
- }
- err = grpc_set_socket_no_sigpipe_if_possible(fd);
- if (err != GRPC_ERROR_NONE) goto error;
-
- GPR_ASSERT(addr->len < ~(socklen_t)0);
- if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
- err = GRPC_OS_ERROR(errno, "bind");
- goto error;
- }
-
- if (listen(fd, get_max_accept_queue_size()) < 0) {
- err = GRPC_OS_ERROR(errno, "listen");
- goto error;
- }
-
- sockname_temp.len = sizeof(struct sockaddr_storage);
-
- if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
- (socklen_t *)&sockname_temp.len) < 0) {
- err = GRPC_OS_ERROR(errno, "getsockname");
- goto error;
- }
-
- *port = grpc_sockaddr_get_port(&sockname_temp);
- return GRPC_ERROR_NONE;
-
-error:
- GPR_ASSERT(err != GRPC_ERROR_NONE);
- if (fd >= 0) {
- close(fd);
- }
- grpc_error *ret = grpc_error_set_int(
- GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
- GRPC_ERROR_INT_FD, fd);
- GRPC_ERROR_UNREF(err);
- return ret;
-}
-
/* event manager callback when reads are ready */
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
grpc_tcp_listener *sp = arg;
@@ -477,216 +309,6 @@ error:
}
}
-static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
- const grpc_resolved_address *addr,
- unsigned port_index, unsigned fd_index,
- grpc_tcp_listener **listener) {
- grpc_tcp_listener *sp = NULL;
- int port = -1;
- char *addr_str;
- char *name;
-
- grpc_error *err = prepare_socket(fd, addr, s->so_reuseport, &port);
- if (err == GRPC_ERROR_NONE) {
- GPR_ASSERT(port > 0);
- grpc_sockaddr_to_string(&addr_str, 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");
- sp = gpr_malloc(sizeof(grpc_tcp_listener));
- sp->next = NULL;
- if (s->head == NULL) {
- s->head = sp;
- } else {
- s->tail->next = sp;
- }
- s->tail = sp;
- sp->server = s;
- sp->fd = fd;
- sp->emfd = grpc_fd_create(fd, name);
- memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
- sp->port = port;
- sp->port_index = port_index;
- sp->fd_index = fd_index;
- sp->is_sibling = 0;
- sp->sibling = NULL;
- GPR_ASSERT(sp->emfd);
- gpr_mu_unlock(&s->mu);
- gpr_free(addr_str);
- gpr_free(name);
- }
-
- *listener = sp;
- return err;
-}
-
-/* If successful, add a listener to s for addr, set *dsmode for the socket, and
- return the *listener. */
-static grpc_error *add_addr_to_server(grpc_tcp_server *s,
- const grpc_resolved_address *addr,
- unsigned port_index, unsigned fd_index,
- grpc_dualstack_mode *dsmode,
- grpc_tcp_listener **listener) {
- grpc_resolved_address addr4_copy;
- int fd;
- grpc_error *err =
- grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
- if (err != GRPC_ERROR_NONE) {
- return err;
- }
- if (*dsmode == GRPC_DSMODE_IPV4 &&
- grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
- addr = &addr4_copy;
- }
- return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
-}
-
-/* Bind to "::" to get a port number not used by any address. */
-static grpc_error *get_unused_port(int *port) {
- grpc_resolved_address wild;
- grpc_sockaddr_make_wildcard6(0, &wild);
- grpc_dualstack_mode dsmode;
- int fd;
- grpc_error *err =
- grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
- if (err != GRPC_ERROR_NONE) {
- return err;
- }
- if (dsmode == GRPC_DSMODE_IPV4) {
- grpc_sockaddr_make_wildcard4(0, &wild);
- }
- if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) {
- err = GRPC_OS_ERROR(errno, "bind");
- close(fd);
- return err;
- }
- if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) !=
- 0) {
- err = GRPC_OS_ERROR(errno, "getsockname");
- close(fd);
- return err;
- }
- close(fd);
- *port = grpc_sockaddr_get_port(&wild);
- return *port <= 0 ? GRPC_ERROR_CREATE("Bad port") : GRPC_ERROR_NONE;
-}
-
-/* Return the listener in s with address addr or NULL. */
-static grpc_tcp_listener *find_listener_with_addr(grpc_tcp_server *s,
- grpc_resolved_address *addr) {
- grpc_tcp_listener *l;
- gpr_mu_lock(&s->mu);
- for (l = s->head; l != NULL; l = l->next) {
- if (l->addr.len != addr->len) {
- continue;
- }
- if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
- break;
- }
- }
- gpr_mu_unlock(&s->mu);
- return l;
-}
-
-/* Get all addresses assigned to network interfaces on the machine and create a
- listener for each. requested_port is the port to use for every listener, or 0
- to select one random port that will be used for every listener. Set *out_port
- to the port selected. Return GRPC_ERROR_NONE only if all listeners were
- added. */
-static grpc_error *add_all_local_addrs_to_server(grpc_tcp_server *s,
- unsigned port_index,
- int requested_port,
- int *out_port) {
- struct ifaddrs *ifa = NULL;
- struct ifaddrs *ifa_it;
- unsigned fd_index = 0;
- grpc_tcp_listener *sp = NULL;
- grpc_error *err = GRPC_ERROR_NONE;
- if (requested_port == 0) {
- /* Note: There could be a race where some local addrs can listen on the
- selected port and some can't. The sane way to handle this would be to
- retry by recreating the whole grpc_tcp_server. Backing out individual
- listeners and orphaning the FDs looks like too much trouble. */
- if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
- return err;
- } else if (requested_port <= 0) {
- return GRPC_ERROR_CREATE("Bad get_unused_port()");
- }
- gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
- }
- if (getifaddrs(&ifa) != 0 || ifa == NULL) {
- return GRPC_OS_ERROR(errno, "getifaddrs");
- }
- for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) {
- grpc_resolved_address addr;
- char *addr_str = NULL;
- grpc_dualstack_mode dsmode;
- grpc_tcp_listener *new_sp = NULL;
- const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
- if (ifa_it->ifa_addr == NULL) {
- continue;
- } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
- addr.len = sizeof(struct sockaddr_in);
- } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
- addr.len = sizeof(struct sockaddr_in6);
- } else {
- continue;
- }
- memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
- if (!grpc_sockaddr_set_port(&addr, requested_port)) {
- /* Should never happen, because we check sa_family above. */
- err = GRPC_ERROR_CREATE("Failed to set port");
- break;
- }
- if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
- addr_str = gpr_strdup("<error>");
- }
- gpr_log(GPR_DEBUG,
- "Adding local addr from interface %s flags 0x%x to server: %s",
- ifa_name, ifa_it->ifa_flags, addr_str);
- /* We could have multiple interfaces with the same address (e.g., bonding),
- so look for duplicates. */
- if (find_listener_with_addr(s, &addr) != NULL) {
- gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
- ifa_name);
- gpr_free(addr_str);
- continue;
- }
- if ((err = add_addr_to_server(s, &addr, port_index, fd_index, &dsmode,
- &new_sp)) != GRPC_ERROR_NONE) {
- char *err_str = NULL;
- grpc_error *root_err;
- if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
- err_str = gpr_strdup("Failed to add listener");
- }
- root_err = GRPC_ERROR_CREATE(err_str);
- gpr_free(err_str);
- gpr_free(addr_str);
- err = grpc_error_add_child(root_err, err);
- break;
- } else {
- GPR_ASSERT(requested_port == new_sp->port);
- ++fd_index;
- if (sp != NULL) {
- new_sp->is_sibling = 1;
- sp->sibling = new_sp;
- }
- sp = new_sp;
- }
- gpr_free(addr_str);
- }
- freeifaddrs(ifa);
- if (err != GRPC_ERROR_NONE) {
- return err;
- } else if (sp == NULL) {
- return GRPC_ERROR_CREATE("No local addresses");
- } else {
- *out_port = sp->port;
- return GRPC_ERROR_NONE;
- }
-}
-
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
unsigned port_index,
@@ -701,14 +323,16 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
grpc_error *v6_err = GRPC_ERROR_NONE;
grpc_error *v4_err = GRPC_ERROR_NONE;
*out_port = -1;
- if (s->expand_wildcard_addrs) {
- return add_all_local_addrs_to_server(s, port_index, requested_port,
- out_port);
+
+ if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) {
+ return grpc_tcp_server_add_all_local_addrs(s, port_index, requested_port,
+ out_port);
}
+
grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6);
/* Try listening on IPv6 first. */
- if ((v6_err = add_addr_to_server(s, &wild6, port_index, fd_index, &dsmode,
- &sp)) == GRPC_ERROR_NONE) {
+ if ((v6_err = grpc_tcp_server_add_addr(s, &wild6, port_index, fd_index,
+ &dsmode, &sp)) == GRPC_ERROR_NONE) {
++fd_index;
requested_port = *out_port = sp->port;
if (dsmode == GRPC_DSMODE_DUALSTACK || dsmode == GRPC_DSMODE_IPV4) {
@@ -717,8 +341,8 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
}
/* If we got a v6-only socket or nothing, try adding 0.0.0.0. */
grpc_sockaddr_set_port(&wild4, requested_port);
- if ((v4_err = add_addr_to_server(s, &wild4, port_index, fd_index, &dsmode,
- &sp2)) == GRPC_ERROR_NONE) {
+ if ((v4_err = grpc_tcp_server_add_addr(s, &wild4, port_index, fd_index,
+ &dsmode, &sp2)) == GRPC_ERROR_NONE) {
*out_port = sp2->port;
if (sp != NULL) {
sp2->is_sibling = 1;
@@ -726,8 +350,20 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
}
}
if (*out_port > 0) {
- GRPC_LOG_IF_ERROR("Failed to add :: listener", v6_err);
- GRPC_LOG_IF_ERROR("Failed to add 0.0.0.0 listener", v4_err);
+ if (v6_err != GRPC_ERROR_NONE) {
+ gpr_log(GPR_INFO,
+ "Failed to add :: listener, "
+ "the environment may not support IPv6: %s",
+ grpc_error_string(v6_err));
+ GRPC_ERROR_UNREF(v6_err);
+ }
+ if (v4_err != GRPC_ERROR_NONE) {
+ gpr_log(GPR_INFO,
+ "Failed to add 0.0.0.0 listener, "
+ "the environment may not support IPv4: %s",
+ grpc_error_string(v4_err));
+ GRPC_ERROR_UNREF(v4_err);
+ }
return GRPC_ERROR_NONE;
} else {
grpc_error *root_err =
@@ -756,7 +392,7 @@ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode,
&fd);
if (err != GRPC_ERROR_NONE) return err;
- err = prepare_socket(fd, &listener->addr, true, &port);
+ err = grpc_tcp_server_prepare_socket(fd, &listener->addr, true, &port);
if (err != GRPC_ERROR_NONE) return err;
listener->server->nports++;
grpc_sockaddr_to_string(&addr_str, &listener->addr, 1);
@@ -828,7 +464,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
addr = &addr6_v4mapped;
}
- if ((err = add_addr_to_server(s, addr, port_index, 0, &dsmode, &sp)) ==
+ if ((err = grpc_tcp_server_add_addr(s, addr, port_index, 0, &dsmode, &sp)) ==
GRPC_ERROR_NONE) {
*out_port = sp->port;
}
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
new file mode 100644
index 0000000000..f5dc8532f9
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
+
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+
+/* one listening port */
+typedef struct grpc_tcp_listener {
+ int fd;
+ grpc_fd *emfd;
+ grpc_tcp_server *server;
+ grpc_resolved_address addr;
+ int port;
+ unsigned port_index;
+ unsigned fd_index;
+ grpc_closure read_closure;
+ grpc_closure destroyed_closure;
+ struct grpc_tcp_listener *next;
+ /* sibling is a linked list of all listeners for a given port. add_port and
+ clone_port place all new listeners in the same sibling list. A member of
+ the 'sibling' list is also a member of the 'next' list. The head of each
+ sibling list has is_sibling==0, and subsequent members of sibling lists
+ have is_sibling==1. is_sibling allows separate sibling lists to be
+ identified while iterating through 'next'. */
+ struct grpc_tcp_listener *sibling;
+ int is_sibling;
+} grpc_tcp_listener;
+
+/* the overall server */
+struct grpc_tcp_server {
+ gpr_refcount refs;
+ /* Called whenever accept() succeeds on a server port. */
+ grpc_tcp_server_cb on_accept_cb;
+ void *on_accept_cb_arg;
+
+ gpr_mu mu;
+
+ /* active port count: how many ports are actually still listening */
+ size_t active_ports;
+ /* destroyed port count: how many ports are completely destroyed */
+ size_t destroyed_ports;
+
+ /* is this server shutting down? */
+ bool shutdown;
+ /* have listeners been shutdown? */
+ bool shutdown_listeners;
+ /* use SO_REUSEPORT */
+ bool so_reuseport;
+ /* expand wildcard addresses to a list of all local addresses */
+ bool expand_wildcard_addrs;
+
+ /* linked list of server ports */
+ grpc_tcp_listener *head;
+ grpc_tcp_listener *tail;
+ unsigned nports;
+
+ /* List of closures passed to shutdown_starting_add(). */
+ grpc_closure_list shutdown_starting;
+
+ /* shutdown callback */
+ grpc_closure *shutdown_complete;
+
+ /* all pollsets interested in new connections */
+ grpc_pollset **pollsets;
+ /* number of pollsets in the pollsets array */
+ size_t pollset_count;
+
+ /* next pollset to assign a channel to */
+ gpr_atm next_pollset_to_assign;
+
+ grpc_resource_quota *resource_quota;
+};
+
+/* If successful, add a listener to \a s for \a addr, set \a dsmode for the
+ socket, and return the \a listener. */
+grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s,
+ const grpc_resolved_address *addr,
+ unsigned port_index, unsigned fd_index,
+ grpc_dualstack_mode *dsmode,
+ grpc_tcp_listener **listener);
+
+/* Get all addresses assigned to network interfaces on the machine and create a
+ listener for each. requested_port is the port to use for every listener, or 0
+ to select one random port that will be used for every listener. Set *out_port
+ to the port selected. Return GRPC_ERROR_NONE only if all listeners were
+ added. */
+grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
+ unsigned port_index,
+ int requested_port,
+ int *out_port);
+
+/* Prepare a recently-created socket for listening. */
+grpc_error *grpc_tcp_server_prepare_socket(int fd,
+ const grpc_resolved_address *addr,
+ bool so_reuseport, int *port);
+/* Ruturn true if the platform supports ifaddrs */
+bool grpc_tcp_server_have_ifaddrs(void);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.c b/src/core/lib/iomgr/tcp_server_utils_posix_common.c
new file mode 100644
index 0000000000..e45e27d5ab
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.c
@@ -0,0 +1,220 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_HAVE_IFADDRS
+
+#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+
+#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
+
+static gpr_once s_init_max_accept_queue_size;
+static int s_max_accept_queue_size;
+
+/* get max listen queue size on linux */
+static void init_max_accept_queue_size(void) {
+ int n = SOMAXCONN;
+ char buf[64];
+ FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
+ if (fp == NULL) {
+ /* 2.4 kernel. */
+ s_max_accept_queue_size = SOMAXCONN;
+ return;
+ }
+ if (fgets(buf, sizeof buf, fp)) {
+ char *end;
+ long i = strtol(buf, &end, 10);
+ if (i > 0 && i <= INT_MAX && end && *end == 0) {
+ n = (int)i;
+ }
+ }
+ fclose(fp);
+ s_max_accept_queue_size = n;
+
+ if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
+ gpr_log(GPR_INFO,
+ "Suspiciously small accept queue (%d) will probably lead to "
+ "connection drops",
+ s_max_accept_queue_size);
+ }
+}
+
+static int get_max_accept_queue_size(void) {
+ gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
+ return s_max_accept_queue_size;
+}
+
+static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
+ const grpc_resolved_address *addr,
+ unsigned port_index, unsigned fd_index,
+ grpc_tcp_listener **listener) {
+ grpc_tcp_listener *sp = NULL;
+ int port = -1;
+ char *addr_str;
+ char *name;
+
+ grpc_error *err =
+ grpc_tcp_server_prepare_socket(fd, addr, s->so_reuseport, &port);
+ if (err == GRPC_ERROR_NONE) {
+ GPR_ASSERT(port > 0);
+ grpc_sockaddr_to_string(&addr_str, 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");
+ sp = gpr_malloc(sizeof(grpc_tcp_listener));
+ sp->next = NULL;
+ if (s->head == NULL) {
+ s->head = sp;
+ } else {
+ s->tail->next = sp;
+ }
+ s->tail = sp;
+ sp->server = s;
+ sp->fd = fd;
+ sp->emfd = grpc_fd_create(fd, name);
+ memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
+ sp->port = port;
+ sp->port_index = port_index;
+ sp->fd_index = fd_index;
+ sp->is_sibling = 0;
+ sp->sibling = NULL;
+ GPR_ASSERT(sp->emfd);
+ gpr_mu_unlock(&s->mu);
+ gpr_free(addr_str);
+ gpr_free(name);
+ }
+
+ *listener = sp;
+ return err;
+}
+
+/* If successful, add a listener to s for addr, set *dsmode for the socket, and
+ return the *listener. */
+grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s,
+ const grpc_resolved_address *addr,
+ unsigned port_index, unsigned fd_index,
+ grpc_dualstack_mode *dsmode,
+ grpc_tcp_listener **listener) {
+ grpc_resolved_address addr4_copy;
+ int fd;
+ grpc_error *err =
+ grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
+ }
+ if (*dsmode == GRPC_DSMODE_IPV4 &&
+ grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
+ addr = &addr4_copy;
+ }
+ return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
+}
+
+/* Prepare a recently-created socket for listening. */
+grpc_error *grpc_tcp_server_prepare_socket(int fd,
+ const grpc_resolved_address *addr,
+ bool so_reuseport, int *port) {
+ grpc_resolved_address sockname_temp;
+ grpc_error *err = GRPC_ERROR_NONE;
+
+ GPR_ASSERT(fd >= 0);
+
+ if (so_reuseport && !grpc_is_unix_socket(addr)) {
+ err = grpc_set_socket_reuse_port(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ }
+
+ err = grpc_set_socket_nonblocking(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_cloexec(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ if (!grpc_is_unix_socket(addr)) {
+ err = grpc_set_socket_low_latency(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_reuse_addr(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ }
+ err = grpc_set_socket_no_sigpipe_if_possible(fd);
+ if (err != GRPC_ERROR_NONE) goto error;
+
+ GPR_ASSERT(addr->len < ~(socklen_t)0);
+ if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
+ err = GRPC_OS_ERROR(errno, "bind");
+ goto error;
+ }
+
+ if (listen(fd, get_max_accept_queue_size()) < 0) {
+ err = GRPC_OS_ERROR(errno, "listen");
+ goto error;
+ }
+
+ sockname_temp.len = sizeof(struct sockaddr_storage);
+
+ if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
+ (socklen_t *)&sockname_temp.len) < 0) {
+ err = GRPC_OS_ERROR(errno, "getsockname");
+ goto error;
+ }
+
+ *port = grpc_sockaddr_get_port(&sockname_temp);
+ return GRPC_ERROR_NONE;
+
+error:
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
+ if (fd >= 0) {
+ close(fd);
+ }
+ grpc_error *ret = grpc_error_set_int(
+ GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
+ GRPC_ERROR_INT_FD, fd);
+ GRPC_ERROR_UNREF(err);
+ return ret;
+}
+
+#endif /* GRPC_HAVE_IFADDRS */
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
new file mode 100644
index 0000000000..6354a6bdc1
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_HAVE_IFADDRS
+
+#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+/* Return the listener in s with address addr or NULL. */
+static grpc_tcp_listener *find_listener_with_addr(grpc_tcp_server *s,
+ grpc_resolved_address *addr) {
+ grpc_tcp_listener *l;
+ gpr_mu_lock(&s->mu);
+ for (l = s->head; l != NULL; l = l->next) {
+ if (l->addr.len != addr->len) {
+ continue;
+ }
+ if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
+ break;
+ }
+ }
+ gpr_mu_unlock(&s->mu);
+ return l;
+}
+
+/* Bind to "::" to get a port number not used by any address. */
+static grpc_error *get_unused_port(int *port) {
+ grpc_resolved_address wild;
+ grpc_sockaddr_make_wildcard6(0, &wild);
+ grpc_dualstack_mode dsmode;
+ int fd;
+ grpc_error *err =
+ grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
+ }
+ if (dsmode == GRPC_DSMODE_IPV4) {
+ grpc_sockaddr_make_wildcard4(0, &wild);
+ }
+ if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) {
+ err = GRPC_OS_ERROR(errno, "bind");
+ close(fd);
+ return err;
+ }
+ if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) !=
+ 0) {
+ err = GRPC_OS_ERROR(errno, "getsockname");
+ close(fd);
+ return err;
+ }
+ close(fd);
+ *port = grpc_sockaddr_get_port(&wild);
+ return *port <= 0 ? GRPC_ERROR_CREATE("Bad port") : GRPC_ERROR_NONE;
+}
+
+grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
+ unsigned port_index,
+ int requested_port,
+ int *out_port) {
+ struct ifaddrs *ifa = NULL;
+ struct ifaddrs *ifa_it;
+ unsigned fd_index = 0;
+ grpc_tcp_listener *sp = NULL;
+ grpc_error *err = GRPC_ERROR_NONE;
+ if (requested_port == 0) {
+ /* Note: There could be a race where some local addrs can listen on the
+ selected port and some can't. The sane way to handle this would be to
+ retry by recreating the whole grpc_tcp_server. Backing out individual
+ listeners and orphaning the FDs looks like too much trouble. */
+ if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
+ return err;
+ } else if (requested_port <= 0) {
+ return GRPC_ERROR_CREATE("Bad get_unused_port()");
+ }
+ gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
+ }
+ if (getifaddrs(&ifa) != 0 || ifa == NULL) {
+ return GRPC_OS_ERROR(errno, "getifaddrs");
+ }
+ for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) {
+ grpc_resolved_address addr;
+ char *addr_str = NULL;
+ grpc_dualstack_mode dsmode;
+ grpc_tcp_listener *new_sp = NULL;
+ const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
+ if (ifa_it->ifa_addr == NULL) {
+ continue;
+ } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
+ addr.len = sizeof(struct sockaddr_in);
+ } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
+ addr.len = sizeof(struct sockaddr_in6);
+ } else {
+ continue;
+ }
+ memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
+ if (!grpc_sockaddr_set_port(&addr, requested_port)) {
+ /* Should never happen, because we check sa_family above. */
+ err = GRPC_ERROR_CREATE("Failed to set port");
+ break;
+ }
+ if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
+ addr_str = gpr_strdup("<error>");
+ }
+ gpr_log(GPR_DEBUG,
+ "Adding local addr from interface %s flags 0x%x to server: %s",
+ ifa_name, ifa_it->ifa_flags, addr_str);
+ /* We could have multiple interfaces with the same address (e.g., bonding),
+ so look for duplicates. */
+ if (find_listener_with_addr(s, &addr) != NULL) {
+ gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
+ ifa_name);
+ gpr_free(addr_str);
+ continue;
+ }
+ if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
+ &new_sp)) != GRPC_ERROR_NONE) {
+ char *err_str = NULL;
+ grpc_error *root_err;
+ if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
+ err_str = gpr_strdup("Failed to add listener");
+ }
+ root_err = GRPC_ERROR_CREATE(err_str);
+ gpr_free(err_str);
+ gpr_free(addr_str);
+ err = grpc_error_add_child(root_err, err);
+ break;
+ } else {
+ GPR_ASSERT(requested_port == new_sp->port);
+ ++fd_index;
+ if (sp != NULL) {
+ new_sp->is_sibling = 1;
+ sp->sibling = new_sp;
+ }
+ sp = new_sp;
+ }
+ gpr_free(addr_str);
+ }
+ freeifaddrs(ifa);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
+ } else if (sp == NULL) {
+ return GRPC_ERROR_CREATE("No local addresses");
+ } else {
+ *out_port = sp->port;
+ return GRPC_ERROR_NONE;
+ }
+}
+
+bool grpc_tcp_server_have_ifaddrs(void) { return true; }
+
+#endif /* GRPC_HAVE_IFADDRS */
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c b/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
new file mode 100644
index 0000000000..95c3198be6
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#if defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS)
+
+#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
+
+grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
+ unsigned port_index,
+ int requested_port,
+ int *out_port) {
+ return GRPC_ERROR_CREATE("no ifaddrs available");
+}
+
+bool grpc_tcp_server_have_ifaddrs(void) { return false; }
+
+#endif /* defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS) */
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 2a1c8d39fa..71e295770a 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -109,8 +109,8 @@ struct grpc_udp_server {
grpc_pollset **pollsets;
/* number of pollsets in the pollsets array */
size_t pollset_count;
- /* The parent grpc server */
- grpc_server *grpc_server;
+ /* opaque object to pass to callbacks */
+ void *user_data;
};
grpc_udp_server *grpc_udp_server_create(void) {
@@ -178,7 +178,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
/* Call the orphan_cb to signal that the FD is about to be closed and
* should no longer be used. */
GPR_ASSERT(sp->orphan_cb);
- sp->orphan_cb(exec_ctx, sp->emfd);
+ sp->orphan_cb(exec_ctx, sp->emfd, sp->server->user_data);
grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
"udp_listener_shutdown");
@@ -204,7 +204,7 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
if (s->active_ports) {
for (sp = s->head; sp; sp = sp->next) {
GPR_ASSERT(sp->orphan_cb);
- sp->orphan_cb(exec_ctx, sp->emfd);
+ sp->orphan_cb(exec_ctx, sp->emfd, sp->server->user_data);
grpc_fd_shutdown(exec_ctx, sp->emfd,
GRPC_ERROR_CREATE("Server destroyed"));
}
@@ -299,7 +299,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
/* Tell the registered callback that data is available to read. */
GPR_ASSERT(sp->read_cb);
- sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
+ sp->read_cb(exec_ctx, sp->emfd, sp->server->user_data);
/* Re-arm the notification event so we get another chance to read. */
grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
@@ -322,7 +322,7 @@ static void on_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
/* Tell the registered callback that the socket is writeable. */
GPR_ASSERT(sp->write_cb);
- sp->write_cb(exec_ctx, sp->emfd);
+ sp->write_cb(exec_ctx, sp->emfd, sp->server->user_data);
/* Re-arm the notification event so we get another chance to write. */
grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure);
@@ -464,13 +464,13 @@ int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) {
void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
grpc_pollset **pollsets, size_t pollset_count,
- grpc_server *server) {
+ void *user_data) {
size_t i;
gpr_mu_lock(&s->mu);
grpc_udp_listener *sp;
GPR_ASSERT(s->active_ports == 0);
s->pollsets = pollsets;
- s->grpc_server = server;
+ s->user_data = user_data;
sp = s->head;
while (sp != NULL) {
@@ -485,7 +485,11 @@ void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
grpc_schedule_on_exec_ctx);
grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure);
- s->active_ports++;
+ /* Registered for both read and write callbacks: increment active_ports
+ * twice to account for this, and delay free-ing of memory until both
+ * on_read and on_write have fired. */
+ s->active_ports += 2;
+
sp = sp->next;
}
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index ed63fa7d81..90842a47f0 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -47,23 +47,23 @@ typedef struct grpc_udp_server grpc_udp_server;
/* Called when data is available to read from the socket. */
typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
- struct grpc_server *server);
+ void *user_data);
/* Called when the socket is writeable. */
-typedef void (*grpc_udp_server_write_cb)(grpc_exec_ctx *exec_ctx,
- grpc_fd *emfd);
+typedef void (*grpc_udp_server_write_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
+ void *user_data);
/* Called when the grpc_fd is about to be orphaned (and the FD closed). */
typedef void (*grpc_udp_server_orphan_cb)(grpc_exec_ctx *exec_ctx,
- grpc_fd *emfd);
+ grpc_fd *emfd, void *user_data);
/* Create a server, initially not bound to any ports */
grpc_udp_server *grpc_udp_server_create(void);
-/* Start listening to bound ports */
+/* Start listening to bound ports. user_data is passed to callbacks. */
void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server,
grpc_pollset **pollsets, size_t pollset_count,
- struct grpc_server *server);
+ void *user_data);
int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index);
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h
index 71d32d97ba..c8dd242c75 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.h
+++ b/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -46,7 +46,7 @@
*
* Setup:
* 1. Before calling anything, call global_init() at least once.
- * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd.
+ * 1. Call grpc_wakeup_fd_init() to set up a wakeup_fd.
* 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file
* descriptors for the poll() style API you are using. Monitor the file
* descriptor for readability.
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index a23082a866..8dea1d98ff 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -318,7 +318,7 @@ static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
call_data *calld = elem->call_data;
grpc_call_credentials_unref(exec_ctx, calld->creds);
if (calld->have_host) {
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 14619d97ca..01cb473177 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -227,7 +227,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {}
+ grpc_closure *ignored) {}
/* Constructor for channel_data */
static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/support/arena.c b/src/core/lib/support/arena.c
new file mode 100644
index 0000000000..7bcb983f24
--- /dev/null
+++ b/src/core/lib/support/arena.c
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/arena.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
+ (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
+
+typedef struct zone {
+ size_t size_begin;
+ size_t size_end;
+ gpr_atm next_atm;
+} zone;
+
+struct gpr_arena {
+ gpr_atm size_so_far;
+ zone initial_zone;
+};
+
+gpr_arena *gpr_arena_create(size_t initial_size) {
+ initial_size = ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
+ gpr_arena *a = gpr_zalloc(sizeof(gpr_arena) + initial_size);
+ a->initial_zone.size_end = initial_size;
+ return a;
+}
+
+size_t gpr_arena_destroy(gpr_arena *arena) {
+ gpr_atm size = gpr_atm_no_barrier_load(&arena->size_so_far);
+ zone *z = (zone *)gpr_atm_no_barrier_load(&arena->initial_zone.next_atm);
+ gpr_free(arena);
+ while (z) {
+ zone *next_z = (zone *)gpr_atm_no_barrier_load(&z->next_atm);
+ gpr_free(z);
+ z = next_z;
+ }
+ return (size_t)size;
+}
+
+void *gpr_arena_alloc(gpr_arena *arena, size_t size) {
+ size = ROUND_UP_TO_ALIGNMENT_SIZE(size);
+ size_t start =
+ (size_t)gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size);
+ zone *z = &arena->initial_zone;
+ while (start > z->size_end) {
+ zone *next_z = (zone *)gpr_atm_acq_load(&z->next_atm);
+ if (next_z == NULL) {
+ size_t next_z_size = (size_t)gpr_atm_no_barrier_load(&arena->size_so_far);
+ next_z = gpr_zalloc(sizeof(zone) + next_z_size);
+ next_z->size_begin = z->size_end;
+ next_z->size_end = z->size_end + next_z_size;
+ if (!gpr_atm_rel_cas(&z->next_atm, (gpr_atm)NULL, (gpr_atm)next_z)) {
+ gpr_free(next_z);
+ next_z = (zone *)gpr_atm_acq_load(&z->next_atm);
+ }
+ }
+ z = next_z;
+ }
+ if (start + size > z->size_end) {
+ return gpr_arena_alloc(arena, size);
+ }
+ GPR_ASSERT(start >= z->size_begin);
+ GPR_ASSERT(start + size <= z->size_end);
+ return ((char *)(z + 1)) + start - z->size_begin;
+}
diff --git a/src/core/lib/support/arena.h b/src/core/lib/support/arena.h
new file mode 100644
index 0000000000..c28033ffc3
--- /dev/null
+++ b/src/core/lib/support/arena.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// \file Arena based allocator
+// Allows very fast allocation of memory, but that memory cannot be freed until
+// the arena as a whole is freed
+// Tracks the total memory allocated against it, so that future arenas can
+// pre-allocate the right amount of memory
+
+#ifndef GRPC_CORE_LIB_SUPPORT_ARENA_H
+#define GRPC_CORE_LIB_SUPPORT_ARENA_H
+
+#include <stddef.h>
+
+typedef struct gpr_arena gpr_arena;
+
+// Create an arena, with \a initial_size bytes in the first allocated buffer
+gpr_arena *gpr_arena_create(size_t initial_size);
+// Allocate \a size bytes from the arena
+void *gpr_arena_alloc(gpr_arena *arena, size_t size);
+// Destroy an arena, returning the total number of bytes allocated
+size_t gpr_arena_destroy(gpr_arena *arena);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_ARENA_H */
diff --git a/src/core/lib/support/sync.c b/src/core/lib/support/sync.c
index e4a7fce646..b52f004f74 100644
--- a/src/core/lib/support/sync.c
+++ b/src/core/lib/support/sync.c
@@ -119,6 +119,10 @@ int gpr_unref(gpr_refcount *r) {
return prior == 1;
}
+int gpr_ref_is_unique(gpr_refcount *r) {
+ return gpr_atm_acq_load(&r->count) == 1;
+}
+
void gpr_stats_init(gpr_stats_counter *c, intptr_t n) {
gpr_atm_rel_store(&c->value, n);
}
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index c2547c5147..2c5d8c0ff3 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -51,6 +51,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/support/arena.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -138,14 +139,15 @@ typedef struct batch_control {
} batch_control;
struct grpc_call {
+ gpr_arena *arena;
grpc_completion_queue *cq;
grpc_polling_entity pollent;
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
gpr_timespec start_time;
- /* TODO(ctiller): share with cq if possible? */
- gpr_mu mu;
+ /* protects first_child, and child next/prev links */
+ gpr_mu child_list_mu;
/* client or server call */
bool is_client;
@@ -160,8 +162,8 @@ struct grpc_call {
bool received_initial_metadata;
bool receiving_message;
bool requested_final_op;
- bool received_final_op;
- bool sent_any_op;
+ gpr_atm any_ops_sent_atm;
+ gpr_atm received_final_op_atm;
/* have we received initial metadata */
bool has_initial_md_been_received;
@@ -212,6 +214,8 @@ struct grpc_call {
grpc_closure receiving_initial_metadata_ready;
uint32_t test_only_last_message_flags;
+ grpc_closure release_call;
+
union {
struct {
grpc_status_code *status;
@@ -273,9 +277,13 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
grpc_channel_get_channel_stack(args->channel);
grpc_call *call;
GPR_TIMER_BEGIN("grpc_call_create", 0);
- call = gpr_zalloc(sizeof(grpc_call) + channel_stack->call_stack_size);
+ gpr_arena *arena =
+ gpr_arena_create(grpc_channel_get_call_size_estimate(args->channel));
+ call = gpr_arena_alloc(arena,
+ sizeof(grpc_call) + channel_stack->call_stack_size);
+ call->arena = arena;
*out_call = call;
- gpr_mu_init(&call->mu);
+ gpr_mu_init(&call->child_list_mu);
call->channel = args->channel;
call->cq = args->cq;
call->parent = args->parent_call;
@@ -313,7 +321,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(call->is_client);
GPR_ASSERT(!args->parent_call->is_client);
- gpr_mu_lock(&args->parent_call->mu);
+ gpr_mu_lock(&args->parent_call->child_list_mu);
if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
send_deadline = gpr_time_min(
@@ -341,6 +349,10 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
}
if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
call->cancellation_is_inherited = 1;
+ if (gpr_atm_acq_load(&args->parent_call->received_final_op_atm)) {
+ cancel_with_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE,
+ GRPC_ERROR_CANCELLED);
+ }
}
if (args->parent_call->first_child == NULL) {
@@ -353,18 +365,23 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
call;
}
- gpr_mu_unlock(&args->parent_call->mu);
+ gpr_mu_unlock(&args->parent_call->child_list_mu);
}
call->send_deadline = send_deadline;
GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
/* initial refcount dropped by grpc_call_destroy */
+ grpc_call_element_args call_args = {
+ .call_stack = CALL_STACK_FROM_CALL(call),
+ .server_transport_data = args->server_transport_data,
+ .context = call->context,
+ .path = path,
+ .start_time = call->start_time,
+ .deadline = send_deadline,
+ .arena = call->arena};
add_init_error(&error, grpc_call_stack_init(exec_ctx, channel_stack, 1,
- destroy_call, call, call->context,
- args->server_transport_data, path,
- call->start_time, send_deadline,
- CALL_STACK_FROM_CALL(call)));
+ destroy_call, call, &call_args));
if (error != GRPC_ERROR_NONE) {
cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
GRPC_ERROR_REF(error));
@@ -421,6 +438,14 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
}
+static void release_call(grpc_exec_ctx *exec_ctx, void *call,
+ grpc_error *error) {
+ grpc_call *c = call;
+ grpc_channel *channel = c->channel;
+ grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(c->arena));
+ GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
+}
+
static void set_status_value_directly(grpc_status_code status, void *dest);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) {
@@ -435,7 +460,7 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
if (c->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
- gpr_mu_destroy(&c->mu);
+ gpr_mu_destroy(&c->child_list_mu);
for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
}
@@ -447,7 +472,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
if (c->cq) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
- grpc_channel *channel = c->channel;
get_final_status(call, set_status_value_directly, &c->final_info.final_status,
NULL);
@@ -456,11 +480,12 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
GRPC_ERROR_UNREF(
- unpack_received_status(gpr_atm_no_barrier_load(&c->status[i])).error);
+ unpack_received_status(gpr_atm_acq_load(&c->status[i])).error);
}
- grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
+ grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info,
+ grpc_closure_init(&c->release_call, release_call, c,
+ grpc_schedule_on_exec_ctx));
GPR_TIMER_END("destroy_call", 0);
}
@@ -473,7 +498,7 @@ void grpc_call_destroy(grpc_call *c) {
GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
if (parent) {
- gpr_mu_lock(&parent->mu);
+ gpr_mu_lock(&parent->child_list_mu);
if (c == parent->first_child) {
parent->first_child = c->sibling_next;
if (c == parent->first_child) {
@@ -482,15 +507,14 @@ void grpc_call_destroy(grpc_call *c) {
c->sibling_prev->sibling_next = c->sibling_next;
c->sibling_next->sibling_prev = c->sibling_prev;
}
- gpr_mu_unlock(&parent->mu);
+ gpr_mu_unlock(&parent->child_list_mu);
GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
}
- gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->destroy_called);
c->destroy_called = 1;
- cancel = c->sent_any_op && !c->received_final_op;
- gpr_mu_unlock(&c->mu);
+ cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) &&
+ !gpr_atm_acq_load(&c->received_final_op_atm);
if (cancel) {
cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE,
GRPC_ERROR_CANCELLED);
@@ -555,53 +579,25 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
"c=%p, status=%d, description=%s, reserved=%p)",
4, (c, (int)status, description, reserved));
GPR_ASSERT(reserved == NULL);
- gpr_mu_lock(&c->mu);
cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status,
description);
- gpr_mu_unlock(&c->mu);
grpc_exec_ctx_finish(&exec_ctx);
return GRPC_CALL_OK;
}
-typedef struct termination_closure {
- grpc_closure closure;
- grpc_call *call;
- grpc_transport_stream_op op;
-} termination_closure;
-
-static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
+static void done_termination(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) {
- termination_closure *tc = tcp;
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "termination");
- gpr_free(tc);
-}
-
-static void send_termination(grpc_exec_ctx *exec_ctx, void *tcp,
- grpc_error *error) {
- termination_closure *tc = tcp;
- memset(&tc->op, 0, sizeof(tc->op));
- tc->op.cancel_error = GRPC_ERROR_REF(error);
- /* reuse closure to catch completion */
- tc->op.on_complete = grpc_closure_init(&tc->closure, done_termination, tc,
- grpc_schedule_on_exec_ctx);
- execute_op(exec_ctx, tc->call, &tc->op);
-}
-
-static void terminate_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_error *error) {
- termination_closure *tc = gpr_malloc(sizeof(*tc));
- memset(tc, 0, sizeof(*tc));
- tc->call = c;
- GRPC_CALL_INTERNAL_REF(tc->call, "termination");
- grpc_closure_sched(exec_ctx, grpc_closure_init(&tc->closure, send_termination,
- tc, grpc_schedule_on_exec_ctx),
- error);
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "termination");
}
static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
status_source source, grpc_error *error) {
+ GRPC_CALL_INTERNAL_REF(c, "termination");
set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
- terminate_with_error(exec_ctx, c, error);
+ grpc_transport_stream_op *op = grpc_make_transport_stream_op(
+ grpc_closure_create(done_termination, c, grpc_schedule_on_exec_ctx));
+ op->cancel_error = error;
+ execute_op(exec_ctx, c, op);
}
static grpc_error *error_from_status(grpc_status_code status,
@@ -715,9 +711,7 @@ static void set_incoming_compression_algorithm(
grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
grpc_call *call) {
grpc_compression_algorithm algorithm;
- gpr_mu_lock(&call->mu);
algorithm = call->incoming_compression_algorithm;
- gpr_mu_unlock(&call->mu);
return algorithm;
}
@@ -729,9 +723,7 @@ static grpc_compression_algorithm compression_algorithm_for_level_locked(
uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
uint32_t flags;
- gpr_mu_lock(&call->mu);
flags = call->test_only_last_message_flags;
- gpr_mu_unlock(&call->mu);
return flags;
}
@@ -785,9 +777,7 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
uint32_t encodings_accepted_by_peer;
- gpr_mu_lock(&call->mu);
encodings_accepted_by_peer = call->encodings_accepted_by_peer;
- gpr_mu_unlock(&call->mu);
return encodings_accepted_by_peer;
}
@@ -1056,7 +1046,7 @@ static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
}
static grpc_error *consolidate_batch_errors(batch_control *bctl) {
- size_t n = (size_t)gpr_atm_no_barrier_load(&bctl->num_errors);
+ size_t n = (size_t)gpr_atm_acq_load(&bctl->num_errors);
if (n == 0) {
return GRPC_ERROR_NONE;
} else if (n == 1) {
@@ -1083,8 +1073,6 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
grpc_call *call = bctl->call;
grpc_error *error = consolidate_batch_errors(bctl);
- gpr_mu_lock(&call->mu);
-
if (bctl->send_initial_metadata) {
grpc_metadata_batch_destroy(
exec_ctx,
@@ -1103,20 +1091,23 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
recv_trailing_filter(exec_ctx, call, md);
- call->received_final_op = true;
/* propagate cancellation to any interested children */
+ gpr_atm_rel_store(&call->received_final_op_atm, 1);
+ gpr_mu_lock(&call->child_list_mu);
child_call = call->first_child;
if (child_call != NULL) {
do {
next_child_call = child_call->sibling_next;
if (child_call->cancellation_is_inherited) {
GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
- grpc_call_cancel(child_call, NULL);
+ cancel_with_error(exec_ctx, child_call, STATUS_FROM_API_OVERRIDE,
+ GRPC_ERROR_CANCELLED);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
}
child_call = next_child_call;
} while (child_call != call->first_child);
}
+ gpr_mu_unlock(&call->child_list_mu);
if (call->is_client) {
get_final_status(call, set_status_value_directly,
@@ -1130,7 +1121,6 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
}
- gpr_mu_unlock(&call->mu);
if (bctl->is_notify_tag_closure) {
/* unrefs bctl->error */
@@ -1221,7 +1211,6 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
- gpr_mu_lock(&bctl->call->mu);
if (error != GRPC_ERROR_NONE) {
if (call->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
@@ -1233,11 +1222,9 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
}
if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
call->receiving_stream == NULL) {
- gpr_mu_unlock(&bctl->call->mu);
process_data_after_md(exec_ctx, bctlp);
} else {
call->saved_receiving_stream_ready_bctlp = bctlp;
- gpr_mu_unlock(&bctl->call->mu);
}
}
@@ -1296,7 +1283,7 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
grpc_error *error, bool has_cancelled) {
if (error == GRPC_ERROR_NONE) return;
- int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
+ int idx = (int)gpr_atm_full_fetch_add(&bctl->num_errors, 1);
if (idx == 0 && !has_cancelled) {
cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE,
GRPC_ERROR_REF(error));
@@ -1309,8 +1296,6 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
- gpr_mu_lock(&call->mu);
-
add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), false);
if (error == GRPC_ERROR_NONE) {
grpc_metadata_batch *md =
@@ -1336,11 +1321,9 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
receiving_stream_ready, call->saved_receiving_stream_ready_bctlp,
grpc_schedule_on_exec_ctx);
call->saved_receiving_stream_ready_bctlp = NULL;
- grpc_closure_sched(exec_ctx, saved_rsr_closure, GRPC_ERROR_REF(error));
+ grpc_closure_run(exec_ctx, saved_rsr_closure, GRPC_ERROR_REF(error));
}
- gpr_mu_unlock(&call->mu);
-
finish_batch_step(exec_ctx, bctl);
}
@@ -1393,7 +1376,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
bctl->notify_tag = notify_tag;
bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
- gpr_mu_lock(&call->mu);
grpc_transport_stream_op *stream_op = &bctl->op;
memset(stream_op, 0, sizeof(*stream_op));
stream_op->covered_by_poller = true;
@@ -1679,8 +1661,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&bctl->finish_batch, finish_batch, bctl,
grpc_schedule_on_exec_ctx);
stream_op->on_complete = &bctl->finish_batch;
- call->sent_any_op = true;
- gpr_mu_unlock(&call->mu);
+ gpr_atm_rel_store(&call->any_ops_sent_atm, 1);
execute_op(exec_ctx, call, stream_op);
@@ -1711,7 +1692,6 @@ done_with_error:
if (bctl->recv_final_op) {
call->requested_final_op = 0;
}
- gpr_mu_unlock(&call->mu);
goto done;
}
@@ -1760,10 +1740,8 @@ uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
grpc_compression_algorithm grpc_call_compression_for_level(
grpc_call *call, grpc_compression_level level) {
- gpr_mu_lock(&call->mu);
grpc_compression_algorithm algo =
compression_algorithm_for_level_locked(call, level);
- gpr_mu_unlock(&call->mu);
return algo;
}
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index d6acd392c1..2b700b2f67 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -68,6 +68,8 @@ struct grpc_channel {
grpc_compression_options compression_options;
grpc_mdelem default_authority;
+ gpr_atm call_size_estimate;
+
gpr_mu registered_call_mu;
registered_call *registered_calls;
@@ -115,6 +117,10 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
+ gpr_atm_no_barrier_store(
+ &channel->call_size_estimate,
+ (gpr_atm)CHANNEL_STACK_FROM_CHANNEL(channel)->call_stack_size);
+
grpc_compression_options_init(&channel->compression_options);
for (size_t i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
@@ -177,6 +183,32 @@ done:
return channel;
}
+size_t grpc_channel_get_call_size_estimate(grpc_channel *channel) {
+#define ROUND_UP_SIZE 256
+ return ((size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate) +
+ ROUND_UP_SIZE) &
+ ~(size_t)(ROUND_UP_SIZE - 1);
+}
+
+void grpc_channel_update_call_size_estimate(grpc_channel *channel,
+ size_t size) {
+ size_t cur = (size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate);
+ if (cur < size) {
+ /* size grew: update estimate */
+ gpr_atm_no_barrier_cas(&channel->call_size_estimate, (gpr_atm)cur,
+ (gpr_atm)size);
+ /* if we lose: never mind, something else will likely update soon enough */
+ } else if (cur == size) {
+ /* no change: holding pattern */
+ } else if (cur > 0) {
+ /* size shrank: decrease estimate */
+ gpr_atm_no_barrier_cas(
+ &channel->call_size_estimate, (gpr_atm)cur,
+ (gpr_atm)(GPR_MIN(cur - 1, (255 * cur + size) / 256)));
+ /* if we lose: never mind, something else will likely update soon enough */
+ }
+}
+
char *grpc_channel_get_target(grpc_channel *channel) {
GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel));
return gpr_strdup(channel->target);
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 3a441d7add..c4aebd8b9b 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -66,6 +66,9 @@ grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
grpc_channel *channel,
int status_code);
+size_t grpc_channel_get_call_size_estimate(grpc_channel *channel);
+void grpc_channel_update_call_size_estimate(grpc_channel *channel, size_t size);
+
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 49bc4c114b..9ddb88bd11 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -130,8 +130,8 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *and_free_memory) {
- gpr_free(and_free_memory);
+ grpc_closure *then_schedule_closure) {
+ grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
}
static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 7ebe130751..acc8b7016a 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -898,7 +898,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {
+ grpc_closure *ignored) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 1143a9e044..ba80bd801e 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -38,4 +38,4 @@
const char *grpc_version_string(void) { return "3.0.0-dev"; }
-const char *grpc_g_stands_for(void) { return "green"; }
+const char *grpc_g_stands_for(void) { return "gentle"; }
diff --git a/src/core/lib/transport/error_utils.c b/src/core/lib/transport/error_utils.c
index da77828d9c..ef55e561fb 100644
--- a/src/core/lib/transport/error_utils.c
+++ b/src/core/lib/transport/error_utils.c
@@ -44,12 +44,12 @@ static grpc_error *recursively_find_error_with_field(grpc_error *error,
}
if (grpc_error_is_special(error)) return NULL;
// Otherwise, search through its children.
- intptr_t key = 0;
- while (true) {
- grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
- if (child_error == NULL) break;
- grpc_error *result = recursively_find_error_with_field(child_error, which);
- if (result != NULL) return result;
+ uint8_t slot = error->first_err;
+ while (slot != UINT8_MAX) {
+ grpc_linked_error *lerr = (grpc_linked_error *)(error->arena + slot);
+ grpc_error *result = recursively_find_error_with_field(lerr->err, which);
+ if (result) return result;
+ slot = lerr->next;
}
return NULL;
}
@@ -112,13 +112,13 @@ bool grpc_error_has_clear_grpc_status(grpc_error *error) {
if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
return true;
}
- intptr_t key = 0;
- while (true) {
- grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
- if (child_error == NULL) break;
- if (grpc_error_has_clear_grpc_status(child_error)) {
+ uint8_t slot = error->first_err;
+ while (slot != UINT8_MAX) {
+ grpc_linked_error *lerr = (grpc_linked_error *)(error->arena + slot);
+ if (grpc_error_has_clear_grpc_status(lerr->err)) {
return true;
}
+ slot = lerr->next;
}
return false;
}
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 165950e288..d56cb31ee0 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -162,9 +162,9 @@ void grpc_transport_destroy(grpc_exec_ctx *exec_ctx,
int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport, grpc_stream *stream,
grpc_stream_refcount *refcount,
- const void *server_data) {
+ const void *server_data, gpr_arena *arena) {
return transport->vtable->init_stream(exec_ctx, transport, stream, refcount,
- server_data);
+ server_data, arena);
}
void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
@@ -197,9 +197,10 @@ void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport,
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- grpc_stream *stream, void *and_free_memory) {
+ grpc_stream *stream,
+ grpc_closure *then_schedule_closure) {
transport->vtable->destroy_stream(exec_ctx, transport, stream,
- and_free_memory);
+ then_schedule_closure);
}
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
@@ -254,8 +255,9 @@ typedef struct {
static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
made_transport_stream_op *op = arg;
- grpc_closure_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error));
+ grpc_closure *c = op->inner_on_complete;
gpr_free(op);
+ grpc_closure_run(exec_ctx, c, GRPC_ERROR_REF(error));
}
grpc_transport_stream_op *grpc_make_transport_stream_op(
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index cc1c277b35..950b18aeda 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -41,6 +41,7 @@
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/support/arena.h"
#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/metadata_batch.h"
@@ -229,7 +230,7 @@ size_t grpc_transport_stream_size(grpc_transport *transport);
int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport, grpc_stream *stream,
grpc_stream_refcount *refcount,
- const void *server_data);
+ const void *server_data, gpr_arena *arena);
void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport,
grpc_stream *stream, grpc_polling_entity *pollent);
@@ -246,7 +247,8 @@ void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport,
caller, but any child memory must be cleaned up) */
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- grpc_stream *stream, void *and_free_memory);
+ grpc_stream *stream,
+ grpc_closure *then_schedule_closure);
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op,
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 8553148c35..6f688bf8d2 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -47,7 +47,7 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_init_stream */
int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
grpc_stream *stream, grpc_stream_refcount *refcount,
- const void *server_data);
+ const void *server_data, gpr_arena *arena);
/* implementation of grpc_transport_set_pollset */
void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
@@ -67,7 +67,8 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_destroy_stream */
void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
- grpc_stream *stream, void *and_free_memory);
+ grpc_stream *stream,
+ grpc_closure *then_schedule_closure);
/* implementation of grpc_transport_destroy */
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index 65f3277499..eddcacc332 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -81,6 +81,16 @@ ChannelArguments::ChannelArguments(const ChannelArguments& other)
}
}
+ChannelArguments::~ChannelArguments() {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ for (auto it = args_.begin(); it != args_.end(); ++it) {
+ if (it->type == GRPC_ARG_POINTER) {
+ it->value.pointer.vtable->destroy(&exec_ctx, it->value.pointer.p);
+ }
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
void ChannelArguments::Swap(ChannelArguments& other) {
args_.swap(other.args_);
strings_.swap(other.strings_);
@@ -101,8 +111,10 @@ void ChannelArguments::SetSocketMutator(grpc_socket_mutator* mutator) {
for (auto it = args_.begin(); it != args_.end(); ++it) {
if (it->type == mutator_arg.type &&
grpc::string(it->key) == grpc::string(mutator_arg.key)) {
+ GPR_ASSERT(!replaced);
it->value.pointer.vtable->destroy(&exec_ctx, it->value.pointer.p);
it->value.pointer = mutator_arg.value.pointer;
+ replaced = true;
}
}
grpc_exec_ctx_finish(&exec_ctx);
@@ -185,7 +197,7 @@ void ChannelArguments::SetPointerWithVtable(
arg.type = GRPC_ARG_POINTER;
strings_.push_back(key);
arg.key = const_cast<char*>(strings_.back().c_str());
- arg.value.pointer.p = value;
+ arg.value.pointer.p = vtable->copy(value);
arg.value.pointer.vtable = vtable;
args_.push_back(arg);
}
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index 79c4bab985..494d5d64d7 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -318,7 +318,8 @@ class ChannelFilter final {
static void DestroyCallElement(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *and_free_memory) {
+ grpc_closure *then_call_closure) {
+ GPR_ASSERT(then_call_closure == NULL);
reinterpret_cast<CallDataType *>(elem->call_data)->~CallDataType();
}
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index 039c530cdc..f5a0e4131d 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -37,5 +37,5 @@
#include <grpc++/grpc++.h>
namespace grpc {
-grpc::string Version() { return "1.2.0-dev"; }
+grpc::string Version() { return "1.3.0-dev"; }
}
diff --git a/src/cpp/server/channel_argument_option.cc b/src/cpp/server/channel_argument_option.cc
new file mode 100644
index 0000000000..723f968ff8
--- /dev/null
+++ b/src/cpp/server/channel_argument_option.cc
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/impl/channel_argument_option.h>
+
+namespace grpc {
+
+std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
+ const grpc::string &name, const grpc::string &value) {
+ class StringOption final : public ServerBuilderOption {
+ public:
+ StringOption(const grpc::string &name, const grpc::string &value)
+ : name_(name), value_(value) {}
+
+ virtual void UpdateArguments(ChannelArguments *args) override {
+ args->SetString(name_, value_);
+ }
+ virtual void UpdatePlugins(
+ std::vector<std::unique_ptr<ServerBuilderPlugin>> *plugins) override {}
+
+ private:
+ const grpc::string name_;
+ const grpc::string value_;
+ };
+ return std::unique_ptr<ServerBuilderOption>(new StringOption(name, value));
+}
+
+std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
+ const grpc::string &name, int value) {
+ class IntOption final : public ServerBuilderOption {
+ public:
+ IntOption(const grpc::string &name, int value)
+ : name_(name), value_(value) {}
+
+ virtual void UpdateArguments(ChannelArguments *args) override {
+ args->SetInt(name_, value_);
+ }
+ virtual void UpdatePlugins(
+ std::vector<std::unique_ptr<ServerBuilderPlugin>> *plugins) override {}
+
+ private:
+ const grpc::string name_;
+ const int value_;
+ };
+ return std::unique_ptr<ServerBuilderOption>(new IntOption(name, value));
+}
+
+} // namespace grpc
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 00a90bb184..4eb4b5a1b2 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -323,9 +323,14 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
}
}
+ bool added_port = false;
for (auto port = ports_.begin(); port != ports_.end(); port++) {
int r = server->AddListeningPort(port->addr, port->creds.get());
- if (!r) return nullptr;
+ if (!r) {
+ if (added_port) server->Shutdown();
+ return nullptr;
+ }
+ added_port = true;
if (port->selected_port != nullptr) {
*port->selected_port = r;
}
@@ -333,6 +338,7 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
if (!server->Start(cqs_data, cqs_.size())) {
+ if (added_port) server->Shutdown();
return nullptr;
}
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 50c4cafa7a..b11ea725e1 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -545,7 +545,7 @@ bool Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
void Server::ShutdownInternal(gpr_timespec deadline) {
std::unique_lock<std::mutex> lock(mu_);
- if (started_ && !shutdown_) {
+ if (!shutdown_) {
shutdown_ = true;
/// The completion queue to use for server shutdown completion notification
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
index 170149ace5..370bf11b2d 100644
--- a/src/csharp/Grpc.Auth/project.json
+++ b/src/csharp/Grpc.Auth/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"title": "gRPC C# Auth",
"authors": [ "Google Inc." ],
"copyright": "Copyright 2015, Google Inc.",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
- "Grpc.Core": "1.2.0-dev",
+ "Grpc.Core": "1.3.0-dev",
"Google.Apis.Auth": "1.21.0"
},
"frameworks": {
diff --git a/src/csharp/Grpc.Core.Testing/project.json b/src/csharp/Grpc.Core.Testing/project.json
index 02be957812..38d5fab50e 100644
--- a/src/csharp/Grpc.Core.Testing/project.json
+++ b/src/csharp/Grpc.Core.Testing/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"title": "gRPC C# Core Testing",
"authors": [ "Google Inc." ],
"copyright": "Copyright 2017, Google Inc.",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
- "Grpc.Core": "1.2.0-dev"
+ "Grpc.Core": "1.3.0-dev"
},
"frameworks": {
"net45": {
diff --git a/src/csharp/Grpc.Core.Tests/TestResult.xml b/src/csharp/Grpc.Core.Tests/TestResult.xml
deleted file mode 100644
index 13da80739c..0000000000
--- a/src/csharp/Grpc.Core.Tests/TestResult.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
-<!--This file represents the results of running a test suite-->
-<test-results name="/usr/local/google/home/jtattermusch/github/grpc/src/csharp/GrpcCoreTests/bin/Debug/GrpcCoreTests.dll" total="3" errors="0" failures="0" not-run="0" inconclusive="0" ignored="0" skipped="0" invalid="0" date="2015-01-29" time="19:40:47">
- <environment nunit-version="2.6.0.0" clr-version="4.0.30319.17020" os-version="Unix 3.13.0.43" platform="Unix" cwd="/usr/local/google/home/jtattermusch/github/grpc/src/csharp/GrpcCoreTests" machine-name="jtattermusch.mtv.corp.google.com" user="jtattermusch" user-domain="jtattermusch.mtv.corp.google.com" />
- <culture-info current-culture="en-US" current-uiculture="en-US" />
- <test-suite type="Assembly" name="/usr/local/google/home/jtattermusch/github/grpc/src/csharp/GrpcCoreTests/bin/Debug/GrpcCoreTests.dll" executed="True" result="Success" success="True" time="0.172" asserts="0">
- <results>
- <test-suite type="Namespace" name="Google" executed="True" result="Success" success="True" time="0.166" asserts="0">
- <results>
- <test-suite type="Namespace" name="GRPC" executed="True" result="Success" success="True" time="0.166" asserts="0">
- <results>
- <test-suite type="Namespace" name="Core" executed="True" result="Success" success="True" time="0.166" asserts="0">
- <results>
- <test-suite type="Namespace" name="Tests" executed="True" result="Success" success="True" time="0.166" asserts="0">
- <results>
- <test-suite type="TestFixture" name="CallsTest" executed="True" result="Success" success="True" time="0.009" asserts="0">
- <results>
- <test-case name="Grpc.Core.Tests.CallsTest.Test1" executed="True" result="Success" success="True" time="0.004" asserts="0" />
- </results>
- </test-suite>
- <test-suite type="TestFixture" name="ClientServerTest" executed="True" result="Success" success="True" time="0.149" asserts="0">
- <results>
- <test-case name="Grpc.Core.Tests.ClientServerTest.EmptyCall" executed="True" result="Success" success="True" time="0.111" asserts="0" />
- </results>
- </test-suite>
- <test-suite type="TestFixture" name="ServerTest" executed="True" result="Success" success="True" time="0.001" asserts="0">
- <results>
- <test-case name="Grpc.Core.Tests.ServerTest.StartAndShutdownServer" executed="True" result="Success" success="True" time="0.001" asserts="0" />
- </results>
- </test-suite>
- </results>
- </test-suite>
- </results>
- </test-suite>
- </results>
- </test-suite>
- </results>
- </test-suite>
- </results>
- </test-suite>
-</test-results> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index f01a024db4..6012d904b6 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.2.0.0";
+ public const string CurrentAssemblyFileVersion = "1.3.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.2.0-dev";
+ public const string CurrentVersion = "1.3.0-dev";
}
}
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
index 0e37ec8927..a1306baa87 100644
--- a/src/csharp/Grpc.Core/project.json
+++ b/src/csharp/Grpc.Core/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"title": "gRPC C# Core",
"authors": [ "Google Inc." ],
"copyright": "Copyright 2015, Google Inc.",
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
index 9e9d245cae..e93d0bf81b 100644
--- a/src/csharp/Grpc.HealthCheck/project.json
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"title": "gRPC C# Healthchecking",
"authors": [ "Google Inc." ],
"copyright": "Copyright 2015, Google Inc.",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
- "Grpc.Core": "1.2.0-dev",
+ "Grpc.Core": "1.3.0-dev",
"Google.Protobuf": "3.2.0"
},
"frameworks": {
diff --git a/src/csharp/Grpc.Reflection/project.json b/src/csharp/Grpc.Reflection/project.json
index 8bfe722f78..014c78e489 100644
--- a/src/csharp/Grpc.Reflection/project.json
+++ b/src/csharp/Grpc.Reflection/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"title": "gRPC C# Reflection",
"authors": [ "Google Inc." ],
"copyright": "Copyright 2016, Google Inc.",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
- "Grpc.Core": "1.2.0-dev",
+ "Grpc.Core": "1.3.0-dev",
"Google.Protobuf": "3.2.0"
},
"frameworks": {
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index b99fdcbdfd..4fec2c71cf 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -28,7 +28,7 @@
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Current package versions
-set VERSION=1.2.0-dev
+set VERSION=1.3.0-dev
set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 442e3acad2..f51b42bc8c 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -66,7 +66,7 @@ dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifa
dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
-nuget pack Grpc.nuspec -Version "1.2.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.2.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
(cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/csharp/global.json b/src/csharp/global.json
new file mode 100644
index 0000000000..32ff399ef9
--- /dev/null
+++ b/src/csharp/global.json
@@ -0,0 +1,5 @@
+{
+ "sdk": {
+ "version": "1.0.0-preview2-003121"
+ }
+} \ No newline at end of file
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 8376339deb..e218f5a406 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-health-check",
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"author": "Google Inc.",
"description": "Health check service for use with gRPC",
"repository": {
@@ -15,7 +15,7 @@
}
],
"dependencies": {
- "grpc": "^1.2.0-dev",
+ "grpc": "^1.3.0-dev",
"lodash": "^3.9.3",
"google-protobuf": "^3.0.0"
},
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 8a7eff507d..a5a0ea2642 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -728,7 +728,7 @@ var defaultHandler = {
* method implementation for the provided service.
*/
Server.prototype.addService = function(service, implementation) {
- if (!_.isObjectLike(service) || !_.isObjectLike(implementation)) {
+ if (!_.isObject(service) || !_.isObject(implementation)) {
throw new Error('addService requires two objects as arguments');
}
if (_.keys(service).length === 0) {
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index 53dd53f539..3096c6e42a 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-tools",
- "version": "1.2.0-dev",
+ "version": "1.3.0-dev",
"author": "Google Inc.",
"description": "Tools for developing with gRPC on Node.js",
"homepage": "http://www.grpc.io/",
diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
index 1a3b775c60..ab8f82a39e 100644
--- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
+++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
- v = '1.2.0-dev'
+ v = '1.3.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index e569faa25b..09155ee4d4 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -38,4 +38,4 @@
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.2.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.3.0-dev"
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 5584246ad9..d964f53e8e 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -90,6 +90,9 @@
return nil;
}
+// This number indicates how many bytes of overhead does Protocol Buffers encoding add onto the
+// message. The number varies as different message.proto is used on different servers. The actual
+// number for each interop server is overridden in corresponding derived test classes.
- (int32_t)encodingOverhead {
return 0;
}
@@ -169,8 +172,6 @@
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
-#ifndef GRPC_COMPILE_WITH_CRONET
-// TODO (mxyan): Fix this test
- (void)testResponsesOverMaxSizeFailWithActionableMessage {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
@@ -191,7 +192,6 @@
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
-#endif
- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
XCTAssertNotNil(self.class.host);
@@ -327,8 +327,6 @@
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
-#ifndef GRPC_COMPILE_WITH_CRONET
-// TODO(makdharma@): Fix this test
- (void)testEmptyStreamRPC {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"];
@@ -342,7 +340,6 @@
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
-#endif
- (void)testCancelAfterBeginRPC {
XCTAssertNotNil(self.class.host);
diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m
index b41210f50f..4987660808 100644
--- a/src/objective-c/tests/InteropTestsLocalCleartext.m
+++ b/src/objective-c/tests/InteropTestsLocalCleartext.m
@@ -37,6 +37,10 @@
static NSString * const kLocalCleartextHost = @"localhost:5050";
+// The Protocol Buffers encoding overhead of local interop server. Acquired
+// by experiment. Adjust this when server's proto file changes.
+static int32_t kLocalInteropServerOverhead = 10;
+
/** Tests in InteropTests.m, sending the RPCs to a local cleartext server. */
@interface InteropTestsLocalCleartext : InteropTests
@end
@@ -48,7 +52,7 @@ static NSString * const kLocalCleartextHost = @"localhost:5050";
}
- (int32_t)encodingOverhead {
- return 10; // bytes
+ return kLocalInteropServerOverhead; // bytes
}
- (void)setUp {
diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m
index 1479c5896c..934d500abc 100644
--- a/src/objective-c/tests/InteropTestsLocalSSL.m
+++ b/src/objective-c/tests/InteropTestsLocalSSL.m
@@ -37,6 +37,10 @@
static NSString * const kLocalSSLHost = @"localhost:5051";
+// The Protocol Buffers encoding overhead of local interop server. Acquired
+// by experiment. Adjust this when server's proto file changes.
+static int32_t kLocalInteropServerOverhead = 10;
+
/** Tests in InteropTests.m, sending the RPCs to a local SSL server. */
@interface InteropTestsLocalSSL : InteropTests
@end
@@ -48,7 +52,7 @@ static NSString * const kLocalSSLHost = @"localhost:5051";
}
- (int32_t)encodingOverhead {
- return 10; // bytes
+ return kLocalInteropServerOverhead; // bytes
}
- (void)setUp {
diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m
index 70f84753bb..9fb30aa43d 100644
--- a/src/objective-c/tests/InteropTestsRemote.m
+++ b/src/objective-c/tests/InteropTestsRemote.m
@@ -37,6 +37,10 @@
static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
+// The Protocol Buffers encoding overhead of remote interop server. Acquired
+// by experiment. Adjust this when server's proto file changes.
+static int32_t kRemoteInteropServerOverhead = 12;
+
/** Tests in InteropTests.m, sending the RPCs to a remote SSL server. */
@interface InteropTestsRemote : InteropTests
@end
@@ -48,7 +52,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
}
- (int32_t)encodingOverhead {
- return 12; // bytes
+ return kRemoteInteropServerOverhead; // bytes
}
@end
diff --git a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
index fab8ad8d25..005bac0a0d 100644
--- a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
+++ b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
@@ -37,6 +37,10 @@
static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
+// The Protocol Buffers encoding overhead of remote interop server. Acquired
+// by experiment. Adjust this when server's proto file changes.
+static int32_t kRemoteInteropServerOverhead = 12;
+
/** Tests in InteropTests.m, sending the RPCs to a remote SSL server. */
@interface InteropTestsRemoteWithCronet : InteropTests
@end
@@ -47,4 +51,8 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
return kRemoteSSLHost;
}
+- (int32_t)encodingOverhead {
+ return kRemoteInteropServerOverhead; // bytes
+}
+
@end
diff --git a/src/php/composer.json b/src/php/composer.json
index 491e34795a..2b140077cc 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Developement use only",
"license": "BSD-3-Clause",
- "version": "1.2.0",
+ "version": "1.3.0",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.1.0"
diff --git a/src/php/tests/qps/client.php b/src/php/tests/qps/client.php
new file mode 100644
index 0000000000..d9ca35ba43
--- /dev/null
+++ b/src/php/tests/qps/client.php
@@ -0,0 +1,166 @@
+<?php
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * PHP client for QPS testing works as follows:
+ * 1. Gets initiated by a call from a proxy that implements the worker service. The
+ * argument to this client is the proxy connection information
+ * 2. Initiate an RPC to the proxy to get ClientConfig
+ * 3. Initiate a client-side telemetry RPC to the proxy
+ * 4. Parse the client config, which includes server target information and then start
+ * a unary or streaming test as appropriate.
+ * 5. After each completed RPC, send its timing to the proxy. The proxy does all histogramming
+ * 6. Proxy will respond on the timing channel when it's time to complete. Our
+ * next timing write will fail and we know that it's time to stop
+ * The above complex dance is since threading and async are not idiomatic and we
+ * shouldn't ever be waiting to read a mark
+ *
+ * This test only supports a single channel since threading/async is not idiomatic
+ * This test supports unary or streaming ping-pongs, as well as open-loop
+ *
+ */
+
+require dirname(__FILE__).'/vendor/autoload.php';
+
+/**
+ * Assertion function that always exits with an error code if the assertion is
+ * falsy.
+ *
+ * @param $value Assertion value. Should be true.
+ * @param $error_message Message to display if the assertion is false
+ */
+function hardAssert($value, $error_message)
+{
+ if (!$value) {
+ echo $error_message."\n";
+ exit(1);
+ }
+}
+
+function hardAssertIfStatusOk($status)
+{
+ if ($status->code !== Grpc\STATUS_OK) {
+ echo "Call did not complete successfully. Status object:\n";
+ var_dump($status);
+ exit(1);
+ }
+}
+
+/* Start the actual client */
+
+function qps_client_main($proxy_address) {
+ echo "Initiating php client\n";
+
+ $proxystubopts = [];
+ $proxystubopts['credentials'] = Grpc\ChannelCredentials::createInsecure();
+ $proxystub = new Grpc\Testing\ProxyClientServiceClient($proxy_address, $proxystubopts);
+ list($config, $status) = $proxystub->GetConfig(new Grpc\Testing\Void())->wait();
+ hardAssertIfStatusOk($status);
+ hardAssert($config->getClientChannels() == 1, "Only 1 channel supported");
+ hardAssert($config->getOutstandingRpcsPerChannel() == 1, "Only 1 outstanding RPC supported");
+
+ echo "Got configuration from proxy, target is " . $config->getServerTargets()[0] . "\n";
+
+ $stubopts = [];
+ if ($config->getSecurityParams()) {
+ if ($config->getSecurityParams()->getUseTestCa()) {
+ $stubopts['credentials'] = Grpc\ChannelCredentials::createSsl(
+ file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
+ } else {
+ $stubopts['credentials'] = Grpc\ChannelCredentials::createSsl(null);
+ }
+ $override = $config->getSecurityParams()->getServerHostOverride();
+ if ($override) {
+ $stubopts['grpc.ssl_target_name_override'] = $override;
+ $stubopts['grpc.default_authority'] = $override;
+ }
+ } else {
+ $stubopts['credentials'] = Grpc\ChannelCredentials::createInsecure();
+ }
+ echo "Initiating php benchmarking client\n";
+
+ $stub = new Grpc\Testing\BenchmarkServiceClient(
+ $config->getServerTargets()[0], $stubopts);
+ $req = new Grpc\Testing\SimpleRequest();
+
+ $req->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
+ $req->setResponseSize($config->getPayloadConfig()->getSimpleParams()->getRespSize());
+ $payload = new Grpc\Testing\Payload();
+ $payload->setType(Grpc\Testing\PayloadType::COMPRESSABLE);
+ $payload->setBody(str_repeat("\0", $config->getPayloadConfig()->getSimpleParams()->getReqSize()));
+ $req->setPayload($payload);
+
+ /* TODO(stanley-cheung): Enable the following by removing the 0&& once protobuf
+ * properly supports oneof in PHP */
+ if (0 && $config->getLoadParams()->getLoad() == "poisson") {
+ $poisson = true;
+ $lamrecip = 1.0/($config->getLoadParams()->getPoisson()->getOfferedLoad());
+ $issue = microtime(true) + $lamrecip * -log(1.0-rand()/(getrandmax()+1));
+ } else {
+ $poisson = false;
+ }
+ $metric = new Grpc\Testing\ProxyStat;
+ $telemetry = $proxystub->ReportTime();
+ if ($config->getRpcType() == Grpc\Testing\RpcType::UNARY) {
+ while (1) {
+ if ($poisson) {
+ time_sleep_until($issue);
+ $issue = $issue + $lamrecip * -log(1.0-rand()/(getrandmax()+1));
+ }
+ $startreq = microtime(true);
+ list($resp,$status) = $stub->UnaryCall($req)->wait();
+ hardAssertIfStatusOk($status);
+ $metric->setLatency(microtime(true)-$startreq);
+ $telemetry->write($metric);
+ }
+ } else {
+ $stream = $stub->StreamingCall();
+ while (1) {
+ if ($poisson) {
+ time_sleep_until($issue);
+ $issue = $issue + $lamrecip * -log(1.0-rand()/(getrandmax()+1));
+ }
+ $startreq = microtime(true);
+ $stream->write($req);
+ $resp = $stream->read();
+ $metric->setLatency(microtime(true)-$startreq);
+ $telemetry->write($metric);
+ }
+ }
+}
+
+ini_set('display_startup_errors', 1);
+ini_set('display_errors', 1);
+error_reporting(-1);
+qps_client_main($argv[1]);
diff --git a/src/php/tests/qps/composer.json b/src/php/tests/qps/composer.json
new file mode 100644
index 0000000000..0fc87098f5
--- /dev/null
+++ b/src/php/tests/qps/composer.json
@@ -0,0 +1,11 @@
+{
+ "minimum-stability": "dev",
+ "require": {
+ "grpc/grpc": "dev-master"
+ },
+ "autoload": {
+ "psr-4": {
+ "": "generated_code/"
+ }
+ }
+}
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php
new file mode 100644
index 0000000000..efca18a0cb
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php
@@ -0,0 +1,127 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class Control
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0add170a247372632f70726f746f2f677270632f74657374696e672f636f" .
+ "6e74726f6c2e70726f746f120c677270632e74657374696e671a25737263" .
+ "2f70726f746f2f677270632f74657374696e672f7061796c6f6164732e70" .
+ "726f746f1a227372632f70726f746f2f677270632f74657374696e672f73" .
+ "746174732e70726f746f22250a0d506f6973736f6e506172616d7312140a" .
+ "0c6f6666657265645f6c6f616418012001280122120a10436c6f7365644c" .
+ "6f6f70506172616d73227b0a0a4c6f6164506172616d7312350a0b636c6f" .
+ "7365645f6c6f6f7018012001280b321e2e677270632e74657374696e672e" .
+ "436c6f7365644c6f6f70506172616d734800122e0a07706f6973736f6e18" .
+ "022001280b321b2e677270632e74657374696e672e506f6973736f6e5061" .
+ "72616d73480042060a046c6f616422430a0e536563757269747950617261" .
+ "6d7312130a0b7573655f746573745f6361180120012808121c0a14736572" .
+ "7665725f686f73745f6f76657272696465180220012809224d0a0a436861" .
+ "6e6e656c417267120c0a046e616d6518012001280912130a097374725f76" .
+ "616c7565180220012809480012130a09696e745f76616c75651803200128" .
+ "05480042070a0576616c756522a0040a0c436c69656e74436f6e66696712" .
+ "160a0e7365727665725f74617267657473180120032809122d0a0b636c69" .
+ "656e745f7479706518022001280e32182e677270632e74657374696e672e" .
+ "436c69656e745479706512350a0f73656375726974795f706172616d7318" .
+ "032001280b321c2e677270632e74657374696e672e536563757269747950" .
+ "6172616d7312240a1c6f75747374616e64696e675f727063735f7065725f" .
+ "6368616e6e656c18042001280512170a0f636c69656e745f6368616e6e65" .
+ "6c73180520012805121c0a146173796e635f636c69656e745f7468726561" .
+ "647318072001280512270a087270635f7479706518082001280e32152e67" .
+ "7270632e74657374696e672e52706354797065122d0a0b6c6f61645f7061" .
+ "72616d73180a2001280b32182e677270632e74657374696e672e4c6f6164" .
+ "506172616d7312330a0e7061796c6f61645f636f6e666967180b2001280b" .
+ "321b2e677270632e74657374696e672e5061796c6f6164436f6e66696712" .
+ "370a10686973746f6772616d5f706172616d73180c2001280b321d2e6772" .
+ "70632e74657374696e672e486973746f6772616d506172616d7312110a09" .
+ "636f72655f6c697374180d2003280512120a0a636f72655f6c696d697418" .
+ "0e2001280512180a106f746865725f636c69656e745f617069180f200128" .
+ "09122e0a0c6368616e6e656c5f6172677318102003280b32182e67727063" .
+ "2e74657374696e672e4368616e6e656c41726722380a0c436c69656e7453" .
+ "746174757312280a05737461747318012001280b32192e677270632e7465" .
+ "7374696e672e436c69656e74537461747322150a044d61726b120d0a0572" .
+ "6573657418012001280822680a0a436c69656e7441726773122b0a057365" .
+ "74757018012001280b321a2e677270632e74657374696e672e436c69656e" .
+ "74436f6e666967480012220a046d61726b18022001280b32122e67727063" .
+ "2e74657374696e672e4d61726b480042090a076172677479706522b4020a" .
+ "0c536572766572436f6e666967122d0a0b7365727665725f747970651801" .
+ "2001280e32182e677270632e74657374696e672e53657276657254797065" .
+ "12350a0f73656375726974795f706172616d7318022001280b321c2e6772" .
+ "70632e74657374696e672e5365637572697479506172616d73120c0a0470" .
+ "6f7274180420012805121c0a146173796e635f7365727665725f74687265" .
+ "61647318072001280512120a0a636f72655f6c696d697418082001280512" .
+ "330a0e7061796c6f61645f636f6e66696718092001280b321b2e67727063" .
+ "2e74657374696e672e5061796c6f6164436f6e66696712110a09636f7265" .
+ "5f6c697374180a2003280512180a106f746865725f7365727665725f6170" .
+ "69180b20012809121c0a137265736f757263655f71756f74615f73697a65" .
+ "18e9072001280522680a0a53657276657241726773122b0a057365747570" .
+ "18012001280b321a2e677270632e74657374696e672e536572766572436f" .
+ "6e666967480012220a046d61726b18022001280b32122e677270632e7465" .
+ "7374696e672e4d61726b480042090a076172677479706522550a0c536572" .
+ "76657253746174757312280a05737461747318012001280b32192e677270" .
+ "632e74657374696e672e5365727665725374617473120c0a04706f727418" .
+ "0220012805120d0a05636f726573180320012805220d0a0b436f72655265" .
+ "7175657374221d0a0c436f7265526573706f6e7365120d0a05636f726573" .
+ "18012001280522060a04566f696422fd010a085363656e6172696f120c0a" .
+ "046e616d6518012001280912310a0d636c69656e745f636f6e6669671802" .
+ "2001280b321a2e677270632e74657374696e672e436c69656e74436f6e66" .
+ "696712130a0b6e756d5f636c69656e747318032001280512310a0d736572" .
+ "7665725f636f6e66696718042001280b321a2e677270632e74657374696e" .
+ "672e536572766572436f6e66696712130a0b6e756d5f7365727665727318" .
+ "052001280512160a0e7761726d75705f7365636f6e647318062001280512" .
+ "190a1162656e63686d61726b5f7365636f6e647318072001280512200a18" .
+ "737061776e5f6c6f63616c5f776f726b65725f636f756e74180820012805" .
+ "22360a095363656e6172696f7312290a097363656e6172696f7318012003" .
+ "280b32162e677270632e74657374696e672e5363656e6172696f22f8020a" .
+ "155363656e6172696f526573756c7453756d6d617279120b0a0371707318" .
+ "0120012801121b0a137170735f7065725f7365727665725f636f72651802" .
+ "20012801121a0a127365727665725f73797374656d5f74696d6518032001" .
+ "280112180a107365727665725f757365725f74696d65180420012801121a" .
+ "0a12636c69656e745f73797374656d5f74696d6518052001280112180a10" .
+ "636c69656e745f757365725f74696d6518062001280112120a0a6c617465" .
+ "6e63795f353018072001280112120a0a6c6174656e63795f393018082001" .
+ "280112120a0a6c6174656e63795f393518092001280112120a0a6c617465" .
+ "6e63795f3939180a2001280112130a0b6c6174656e63795f393939180b20" .
+ "01280112180a107365727665725f6370755f7573616765180c2001280112" .
+ "260a1e7375636365737366756c5f72657175657374735f7065725f736563" .
+ "6f6e64180d2001280112220a1a6661696c65645f72657175657374735f70" .
+ "65725f7365636f6e64180e200128012283030a0e5363656e6172696f5265" .
+ "73756c7412280a087363656e6172696f18012001280b32162e677270632e" .
+ "74657374696e672e5363656e6172696f122e0a096c6174656e6369657318" .
+ "022001280b321b2e677270632e74657374696e672e486973746f6772616d" .
+ "44617461122f0a0c636c69656e745f737461747318032003280b32192e67" .
+ "7270632e74657374696e672e436c69656e745374617473122f0a0c736572" .
+ "7665725f737461747318042003280b32192e677270632e74657374696e67" .
+ "2e536572766572537461747312140a0c7365727665725f636f7265731805" .
+ "2003280512340a0773756d6d61727918062001280b32232e677270632e74" .
+ "657374696e672e5363656e6172696f526573756c7453756d6d6172791216" .
+ "0a0e636c69656e745f7375636365737318072003280812160a0e73657276" .
+ "65725f7375636365737318082003280812390a0f726571756573745f7265" .
+ "73756c747318092003280b32202e677270632e74657374696e672e526571" .
+ "75657374526573756c74436f756e742a410a0a436c69656e745479706512" .
+ "0f0a0b53594e435f434c49454e54100012100a0c4153594e435f434c4945" .
+ "4e54100112100a0c4f544845525f434c49454e5410022a5b0a0a53657276" .
+ "657254797065120f0a0b53594e435f534552564552100012100a0c415359" .
+ "4e435f534552564552100112180a144153594e435f47454e455249435f53" .
+ "4552564552100212100a0c4f544845525f53455256455210032a230a0752" .
+ "70635479706512090a05554e4152591000120d0a0953545245414d494e47" .
+ "1001620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Messages.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Messages.php
new file mode 100644
index 0000000000..c088002626
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Messages.php
@@ -0,0 +1,69 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class Messages
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0ad50a0a257372632f70726f746f2f677270632f74657374696e672f6d65" .
+ "7373616765732e70726f746f120c677270632e74657374696e67221a0a09" .
+ "426f6f6c56616c7565120d0a0576616c756518012001280822400a075061" .
+ "796c6f616412270a047479706518012001280e32192e677270632e746573" .
+ "74696e672e5061796c6f616454797065120c0a04626f647918022001280c" .
+ "222b0a0a4563686f537461747573120c0a04636f6465180120012805120f" .
+ "0a076d65737361676518022001280922ce020a0d53696d706c6552657175" .
+ "65737412300a0d726573706f6e73655f7479706518012001280e32192e67" .
+ "7270632e74657374696e672e5061796c6f61645479706512150a0d726573" .
+ "706f6e73655f73697a6518022001280512260a077061796c6f6164180320" .
+ "01280b32152e677270632e74657374696e672e5061796c6f616412150a0d" .
+ "66696c6c5f757365726e616d6518042001280812180a1066696c6c5f6f61" .
+ "7574685f73636f706518052001280812340a13726573706f6e73655f636f" .
+ "6d7072657373656418062001280b32172e677270632e74657374696e672e" .
+ "426f6f6c56616c756512310a0f726573706f6e73655f7374617475731807" .
+ "2001280b32182e677270632e74657374696e672e4563686f537461747573" .
+ "12320a116578706563745f636f6d7072657373656418082001280b32172e" .
+ "677270632e74657374696e672e426f6f6c56616c7565225f0a0e53696d70" .
+ "6c65526573706f6e736512260a077061796c6f616418012001280b32152e" .
+ "677270632e74657374696e672e5061796c6f616412100a08757365726e61" .
+ "6d6518022001280912130a0b6f617574685f73636f706518032001280922" .
+ "770a1953747265616d696e67496e70757443616c6c526571756573741226" .
+ "0a077061796c6f616418012001280b32152e677270632e74657374696e67" .
+ "2e5061796c6f616412320a116578706563745f636f6d7072657373656418" .
+ "022001280b32172e677270632e74657374696e672e426f6f6c56616c7565" .
+ "223d0a1a53747265616d696e67496e70757443616c6c526573706f6e7365" .
+ "121f0a17616767726567617465645f7061796c6f61645f73697a65180120" .
+ "01280522640a12526573706f6e7365506172616d6574657273120c0a0473" .
+ "697a6518012001280512130a0b696e74657276616c5f7573180220012805" .
+ "122b0a0a636f6d7072657373656418032001280b32172e677270632e7465" .
+ "7374696e672e426f6f6c56616c756522e8010a1a53747265616d696e674f" .
+ "757470757443616c6c5265717565737412300a0d726573706f6e73655f74" .
+ "79706518012001280e32192e677270632e74657374696e672e5061796c6f" .
+ "616454797065123d0a13726573706f6e73655f706172616d657465727318" .
+ "022003280b32202e677270632e74657374696e672e526573706f6e736550" .
+ "6172616d657465727312260a077061796c6f616418032001280b32152e67" .
+ "7270632e74657374696e672e5061796c6f616412310a0f726573706f6e73" .
+ "655f73746174757318072001280b32182e677270632e74657374696e672e" .
+ "4563686f53746174757322450a1b53747265616d696e674f757470757443" .
+ "616c6c526573706f6e736512260a077061796c6f616418012001280b3215" .
+ "2e677270632e74657374696e672e5061796c6f616422330a0f5265636f6e" .
+ "6e656374506172616d7312200a186d61785f7265636f6e6e6563745f6261" .
+ "636b6f66665f6d7318012001280522330a0d5265636f6e6e656374496e66" .
+ "6f120e0a0670617373656418012001280812120a0a6261636b6f66665f6d" .
+ "731802200328052a1f0a0b5061796c6f61645479706512100a0c434f4d50" .
+ "5245535341424c451000620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Payloads.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Payloads.php
new file mode 100644
index 0000000000..279fe00ac8
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Payloads.php
@@ -0,0 +1,37 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class Payloads
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0a93030a257372632f70726f746f2f677270632f74657374696e672f7061" .
+ "796c6f6164732e70726f746f120c677270632e74657374696e6722370a10" .
+ "42797465427566666572506172616d7312100a087265715f73697a651801" .
+ "2001280512110a09726573705f73697a6518022001280522380a1153696d" .
+ "706c6550726f746f506172616d7312100a087265715f73697a6518012001" .
+ "280512110a09726573705f73697a6518022001280522140a12436f6d706c" .
+ "657850726f746f506172616d7322ca010a0d5061796c6f6164436f6e6669" .
+ "6712380a0e627974656275665f706172616d7318012001280b321e2e6772" .
+ "70632e74657374696e672e42797465427566666572506172616d73480012" .
+ "380a0d73696d706c655f706172616d7318022001280b321f2e677270632e" .
+ "74657374696e672e53696d706c6550726f746f506172616d734800123a0a" .
+ "0e636f6d706c65785f706172616d7318032001280b32202e677270632e74" .
+ "657374696e672e436f6d706c657850726f746f506172616d73480042090a" .
+ "077061796c6f6164620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php
new file mode 100644
index 0000000000..e35944e1d8
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php
@@ -0,0 +1,34 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/proxy-service.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class ProxyService
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0a97020a2a7372632f70726f746f2f677270632f74657374696e672f7072" .
+ "6f78792d736572766963652e70726f746f120c677270632e74657374696e" .
+ "671a247372632f70726f746f2f677270632f74657374696e672f636f6e74" .
+ "726f6c2e70726f746f221c0a0950726f787953746174120f0a076c617465" .
+ "6e6379180120012801328e010a1250726f7879436c69656e745365727669" .
+ "6365123b0a09476574436f6e66696712122e677270632e74657374696e67" .
+ "2e566f69641a1a2e677270632e74657374696e672e436c69656e74436f6e" .
+ "666967123b0a0a5265706f727454696d6512172e677270632e7465737469" .
+ "6e672e50726f7879537461741a122e677270632e74657374696e672e566f" .
+ "69642801620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php
new file mode 100644
index 0000000000..7a9439a5b9
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php
@@ -0,0 +1,45 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/services.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class Services
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0ad1040a257372632f70726f746f2f677270632f74657374696e672f7365" .
+ "7276696365732e70726f746f120c677270632e74657374696e671a257372" .
+ "632f70726f746f2f677270632f74657374696e672f6d657373616765732e" .
+ "70726f746f1a247372632f70726f746f2f677270632f74657374696e672f" .
+ "636f6e74726f6c2e70726f746f32aa010a1042656e63686d61726b536572" .
+ "7669636512460a09556e61727943616c6c121b2e677270632e7465737469" .
+ "6e672e53696d706c65526571756573741a1c2e677270632e74657374696e" .
+ "672e53696d706c65526573706f6e7365124e0a0d53747265616d696e6743" .
+ "616c6c121b2e677270632e74657374696e672e53696d706c655265717565" .
+ "73741a1c2e677270632e74657374696e672e53696d706c65526573706f6e" .
+ "7365280130013297020a0d576f726b65725365727669636512450a095275" .
+ "6e53657276657212182e677270632e74657374696e672e53657276657241" .
+ "7267731a1a2e677270632e74657374696e672e5365727665725374617475" .
+ "732801300112450a0952756e436c69656e7412182e677270632e74657374" .
+ "696e672e436c69656e74417267731a1a2e677270632e74657374696e672e" .
+ "436c69656e745374617475732801300112420a09436f7265436f756e7412" .
+ "192e677270632e74657374696e672e436f7265526571756573741a1a2e67" .
+ "7270632e74657374696e672e436f7265526573706f6e736512340a0a5175" .
+ "6974576f726b657212122e677270632e74657374696e672e566f69641a12" .
+ "2e677270632e74657374696e672e566f6964620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php
new file mode 100644
index 0000000000..99c0000a52
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php
@@ -0,0 +1,44 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Testing;
+
+class Stats
+{
+ public static $is_initialized = false;
+
+ public static function initOnce() {
+ $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+ if (static::$is_initialized == true) {
+ return;
+ }
+ $pool->internalAddGeneratedFile(hex2bin(
+ "0adf040a227372632f70726f746f2f677270632f74657374696e672f7374" .
+ "6174732e70726f746f120c677270632e74657374696e67227a0a0b536572" .
+ "766572537461747312140a0c74696d655f656c6170736564180120012801" .
+ "12110a0974696d655f7573657218022001280112130a0b74696d655f7379" .
+ "7374656d18032001280112160a0e746f74616c5f6370755f74696d651804" .
+ "2001280412150a0d69646c655f6370755f74696d65180520012804223b0a" .
+ "0f486973746f6772616d506172616d7312120a0a7265736f6c7574696f6e" .
+ "18012001280112140a0c6d61785f706f737369626c651802200128012277" .
+ "0a0d486973746f6772616d44617461120e0a066275636b65741801200328" .
+ "0d12100a086d696e5f7365656e18022001280112100a086d61785f736565" .
+ "6e180320012801120b0a0373756d18042001280112160a0e73756d5f6f66" .
+ "5f73717561726573180520012801120d0a05636f756e7418062001280122" .
+ "380a1252657175657374526573756c74436f756e7412130a0b7374617475" .
+ "735f636f6465180120012805120d0a05636f756e7418022001280322b601" .
+ "0a0b436c69656e745374617473122e0a096c6174656e6369657318012001" .
+ "280b321b2e677270632e74657374696e672e486973746f6772616d446174" .
+ "6112140a0c74696d655f656c617073656418022001280112110a0974696d" .
+ "655f7573657218032001280112130a0b74696d655f73797374656d180420" .
+ "01280112390a0f726571756573745f726573756c747318052003280b3220" .
+ "2e677270632e74657374696e672e52657175657374526573756c74436f75" .
+ "6e74620670726f746f33"
+ ));
+
+ static::$is_initialized = true;
+ }
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php
new file mode 100644
index 0000000000..daf17800cd
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php
@@ -0,0 +1,78 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// 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.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+namespace Grpc\Testing {
+
+ class BenchmarkServiceClient extends \Grpc\BaseStub {
+
+ /**
+ * @param string $hostname hostname
+ * @param array $opts channel options
+ * @param Grpc\Channel $channel (optional) re-use channel object
+ */
+ public function __construct($hostname, $opts, $channel = null) {
+ parent::__construct($hostname, $opts, $channel);
+ }
+
+ /**
+ * One request followed by one response.
+ * The server returns the client payload as-is.
+ * @param \Grpc\Testing\SimpleRequest $argument input argument
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function UnaryCall(\Grpc\Testing\SimpleRequest $argument,
+ $metadata = [], $options = []) {
+ return $this->_simpleRequest('/grpc.testing.BenchmarkService/UnaryCall',
+ $argument,
+ ['\Grpc\Testing\SimpleResponse', 'decode'],
+ $metadata, $options);
+ }
+
+ /**
+ * One request followed by one response.
+ * The server returns the client payload as-is.
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function StreamingCall($metadata = [], $options = []) {
+ return $this->_bidiRequest('/grpc.testing.BenchmarkService/StreamingCall',
+ ['\Grpc\Testing\SimpleResponse','decode'],
+ $metadata, $options);
+ }
+
+ }
+
+}
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php b/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php
new file mode 100644
index 0000000000..f0497accfb
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php
@@ -0,0 +1,62 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * TODO(dgq): Go back to using well-known types once
+ * https://github.com/grpc/grpc/issues/6980 has been fixed.
+ * import "google/protobuf/wrappers.proto";
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.BoolValue</code>
+ */
+class BoolValue extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * The bool value.
+ * </pre>
+ *
+ * <code>bool value = 1;</code>
+ */
+ private $value = false;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * The bool value.
+ * </pre>
+ *
+ * <code>bool value = 1;</code>
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * <pre>
+ * The bool value.
+ * </pre>
+ *
+ * <code>bool value = 1;</code>
+ */
+ public function setValue($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->value = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php
new file mode 100644
index 0000000000..0057d38748
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php
@@ -0,0 +1,65 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ByteBufferParams</code>
+ */
+class ByteBufferParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ private $req_size = 0;
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ private $resp_size = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ public function getReqSize()
+ {
+ return $this->req_size;
+ }
+
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ public function setReqSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->req_size = $var;
+ }
+
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ public function getRespSize()
+ {
+ return $this->resp_size;
+ }
+
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ public function setRespSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->resp_size = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php b/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php
new file mode 100644
index 0000000000..d2fe3ae5ff
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php
@@ -0,0 +1,84 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ChannelArg</code>
+ */
+class ChannelArg extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>string name = 1;</code>
+ */
+ private $name = '';
+ protected $value;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>string name = 1;</code>
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * <code>string name = 1;</code>
+ */
+ public function setName($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->name = $var;
+ }
+
+ /**
+ * <code>string str_value = 2;</code>
+ */
+ public function getStrValue()
+ {
+ return $this->readOneof(2);
+ }
+
+ /**
+ * <code>string str_value = 2;</code>
+ */
+ public function setStrValue($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->writeOneof(2, $var);
+ }
+
+ /**
+ * <code>int32 int_value = 3;</code>
+ */
+ public function getIntValue()
+ {
+ return $this->readOneof(3);
+ }
+
+ /**
+ * <code>int32 int_value = 3;</code>
+ */
+ public function setIntValue($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->writeOneof(3, $var);
+ }
+
+ public function getValue()
+ {
+ return $this->whichOneof("value");
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php
new file mode 100644
index 0000000000..c878c5a7bc
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php
@@ -0,0 +1,63 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ClientArgs</code>
+ */
+class ClientArgs extends \Google\Protobuf\Internal\Message
+{
+ protected $argtype;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ClientConfig setup = 1;</code>
+ */
+ public function getSetup()
+ {
+ return $this->readOneof(1);
+ }
+
+ /**
+ * <code>.grpc.testing.ClientConfig setup = 1;</code>
+ */
+ public function setSetup(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ClientConfig::class);
+ $this->writeOneof(1, $var);
+ }
+
+ /**
+ * <code>.grpc.testing.Mark mark = 2;</code>
+ */
+ public function getMark()
+ {
+ return $this->readOneof(2);
+ }
+
+ /**
+ * <code>.grpc.testing.Mark mark = 2;</code>
+ */
+ public function setMark(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Mark::class);
+ $this->writeOneof(2, $var);
+ }
+
+ public function getArgtype()
+ {
+ return $this->whichOneof("argtype");
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php
new file mode 100644
index 0000000000..52d6a75fb0
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php
@@ -0,0 +1,407 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ClientConfig</code>
+ */
+class ClientConfig extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * List of targets to connect to. At least one target needs to be specified.
+ * </pre>
+ *
+ * <code>repeated string server_targets = 1;</code>
+ */
+ private $server_targets;
+ /**
+ * <code>.grpc.testing.ClientType client_type = 2;</code>
+ */
+ private $client_type = 0;
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+ */
+ private $security_params = null;
+ /**
+ * <pre>
+ * How many concurrent RPCs to start for each channel.
+ * For synchronous client, use a separate thread for each outstanding RPC.
+ * </pre>
+ *
+ * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+ */
+ private $outstanding_rpcs_per_channel = 0;
+ /**
+ * <pre>
+ * Number of independent client channels to create.
+ * i-th channel will connect to server_target[i % server_targets.size()]
+ * </pre>
+ *
+ * <code>int32 client_channels = 5;</code>
+ */
+ private $client_channels = 0;
+ /**
+ * <pre>
+ * Only for async client. Number of threads to use to start/manage RPCs.
+ * </pre>
+ *
+ * <code>int32 async_client_threads = 7;</code>
+ */
+ private $async_client_threads = 0;
+ /**
+ * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+ */
+ private $rpc_type = 0;
+ /**
+ * <pre>
+ * The requested load for the entire client (aggregated over all the threads).
+ * </pre>
+ *
+ * <code>.grpc.testing.LoadParams load_params = 10;</code>
+ */
+ private $load_params = null;
+ /**
+ * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+ */
+ private $payload_config = null;
+ /**
+ * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+ */
+ private $histogram_params = null;
+ /**
+ * <pre>
+ * Specify the cores we should run the client on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 13;</code>
+ */
+ private $core_list;
+ /**
+ * <code>int32 core_limit = 14;</code>
+ */
+ private $core_limit = 0;
+ /**
+ * <pre>
+ * If we use an OTHER_CLIENT client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_client_api = 15;</code>
+ */
+ private $other_client_api = '';
+ /**
+ * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+ */
+ private $channel_args;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * List of targets to connect to. At least one target needs to be specified.
+ * </pre>
+ *
+ * <code>repeated string server_targets = 1;</code>
+ */
+ public function getServerTargets()
+ {
+ return $this->server_targets;
+ }
+
+ /**
+ * <pre>
+ * List of targets to connect to. At least one target needs to be specified.
+ * </pre>
+ *
+ * <code>repeated string server_targets = 1;</code>
+ */
+ public function setServerTargets(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING);
+ $this->server_targets = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.ClientType client_type = 2;</code>
+ */
+ public function getClientType()
+ {
+ return $this->client_type;
+ }
+
+ /**
+ * <code>.grpc.testing.ClientType client_type = 2;</code>
+ */
+ public function setClientType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\ClientType::class);
+ $this->client_type = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+ */
+ public function getSecurityParams()
+ {
+ return $this->security_params;
+ }
+
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+ */
+ public function setSecurityParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\SecurityParams::class);
+ $this->security_params = $var;
+ }
+
+ /**
+ * <pre>
+ * How many concurrent RPCs to start for each channel.
+ * For synchronous client, use a separate thread for each outstanding RPC.
+ * </pre>
+ *
+ * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+ */
+ public function getOutstandingRpcsPerChannel()
+ {
+ return $this->outstanding_rpcs_per_channel;
+ }
+
+ /**
+ * <pre>
+ * How many concurrent RPCs to start for each channel.
+ * For synchronous client, use a separate thread for each outstanding RPC.
+ * </pre>
+ *
+ * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+ */
+ public function setOutstandingRpcsPerChannel($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->outstanding_rpcs_per_channel = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of independent client channels to create.
+ * i-th channel will connect to server_target[i % server_targets.size()]
+ * </pre>
+ *
+ * <code>int32 client_channels = 5;</code>
+ */
+ public function getClientChannels()
+ {
+ return $this->client_channels;
+ }
+
+ /**
+ * <pre>
+ * Number of independent client channels to create.
+ * i-th channel will connect to server_target[i % server_targets.size()]
+ * </pre>
+ *
+ * <code>int32 client_channels = 5;</code>
+ */
+ public function setClientChannels($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->client_channels = $var;
+ }
+
+ /**
+ * <pre>
+ * Only for async client. Number of threads to use to start/manage RPCs.
+ * </pre>
+ *
+ * <code>int32 async_client_threads = 7;</code>
+ */
+ public function getAsyncClientThreads()
+ {
+ return $this->async_client_threads;
+ }
+
+ /**
+ * <pre>
+ * Only for async client. Number of threads to use to start/manage RPCs.
+ * </pre>
+ *
+ * <code>int32 async_client_threads = 7;</code>
+ */
+ public function setAsyncClientThreads($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->async_client_threads = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+ */
+ public function getRpcType()
+ {
+ return $this->rpc_type;
+ }
+
+ /**
+ * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+ */
+ public function setRpcType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\RpcType::class);
+ $this->rpc_type = $var;
+ }
+
+ /**
+ * <pre>
+ * The requested load for the entire client (aggregated over all the threads).
+ * </pre>
+ *
+ * <code>.grpc.testing.LoadParams load_params = 10;</code>
+ */
+ public function getLoadParams()
+ {
+ return $this->load_params;
+ }
+
+ /**
+ * <pre>
+ * The requested load for the entire client (aggregated over all the threads).
+ * </pre>
+ *
+ * <code>.grpc.testing.LoadParams load_params = 10;</code>
+ */
+ public function setLoadParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\LoadParams::class);
+ $this->load_params = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+ */
+ public function getPayloadConfig()
+ {
+ return $this->payload_config;
+ }
+
+ /**
+ * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+ */
+ public function setPayloadConfig(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\PayloadConfig::class);
+ $this->payload_config = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+ */
+ public function getHistogramParams()
+ {
+ return $this->histogram_params;
+ }
+
+ /**
+ * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+ */
+ public function setHistogramParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\HistogramParams::class);
+ $this->histogram_params = $var;
+ }
+
+ /**
+ * <pre>
+ * Specify the cores we should run the client on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 13;</code>
+ */
+ public function getCoreList()
+ {
+ return $this->core_list;
+ }
+
+ /**
+ * <pre>
+ * Specify the cores we should run the client on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 13;</code>
+ */
+ public function setCoreList(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+ $this->core_list = $var;
+ }
+
+ /**
+ * <code>int32 core_limit = 14;</code>
+ */
+ public function getCoreLimit()
+ {
+ return $this->core_limit;
+ }
+
+ /**
+ * <code>int32 core_limit = 14;</code>
+ */
+ public function setCoreLimit($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->core_limit = $var;
+ }
+
+ /**
+ * <pre>
+ * If we use an OTHER_CLIENT client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_client_api = 15;</code>
+ */
+ public function getOtherClientApi()
+ {
+ return $this->other_client_api;
+ }
+
+ /**
+ * <pre>
+ * If we use an OTHER_CLIENT client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_client_api = 15;</code>
+ */
+ public function setOtherClientApi($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->other_client_api = $var;
+ }
+
+ /**
+ * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+ */
+ public function getChannelArgs()
+ {
+ return $this->channel_args;
+ }
+
+ /**
+ * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+ */
+ public function setChannelArgs(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ChannelArg::class);
+ $this->channel_args = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php
new file mode 100644
index 0000000000..8b9a0c33a4
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php
@@ -0,0 +1,164 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ClientStats</code>
+ */
+class ClientStats extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Latency histogram. Data points are in nanoseconds.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 1;</code>
+ */
+ private $latencies = null;
+ /**
+ * <pre>
+ * See ServerStats for details.
+ * </pre>
+ *
+ * <code>double time_elapsed = 2;</code>
+ */
+ private $time_elapsed = 0.0;
+ /**
+ * <code>double time_user = 3;</code>
+ */
+ private $time_user = 0.0;
+ /**
+ * <code>double time_system = 4;</code>
+ */
+ private $time_system = 0.0;
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+ */
+ private $request_results;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Latency histogram. Data points are in nanoseconds.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 1;</code>
+ */
+ public function getLatencies()
+ {
+ return $this->latencies;
+ }
+
+ /**
+ * <pre>
+ * Latency histogram. Data points are in nanoseconds.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 1;</code>
+ */
+ public function setLatencies(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\HistogramData::class);
+ $this->latencies = $var;
+ }
+
+ /**
+ * <pre>
+ * See ServerStats for details.
+ * </pre>
+ *
+ * <code>double time_elapsed = 2;</code>
+ */
+ public function getTimeElapsed()
+ {
+ return $this->time_elapsed;
+ }
+
+ /**
+ * <pre>
+ * See ServerStats for details.
+ * </pre>
+ *
+ * <code>double time_elapsed = 2;</code>
+ */
+ public function setTimeElapsed($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_elapsed = $var;
+ }
+
+ /**
+ * <code>double time_user = 3;</code>
+ */
+ public function getTimeUser()
+ {
+ return $this->time_user;
+ }
+
+ /**
+ * <code>double time_user = 3;</code>
+ */
+ public function setTimeUser($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_user = $var;
+ }
+
+ /**
+ * <code>double time_system = 4;</code>
+ */
+ public function getTimeSystem()
+ {
+ return $this->time_system;
+ }
+
+ /**
+ * <code>double time_system = 4;</code>
+ */
+ public function setTimeSystem($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_system = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+ */
+ public function getRequestResults()
+ {
+ return $this->request_results;
+ }
+
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+ */
+ public function setRequestResults(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
+ $this->request_results = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php
new file mode 100644
index 0000000000..a59f87a962
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php
@@ -0,0 +1,44 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ClientStatus</code>
+ */
+class ClientStatus extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>.grpc.testing.ClientStats stats = 1;</code>
+ */
+ private $stats = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ClientStats stats = 1;</code>
+ */
+ public function getStats()
+ {
+ return $this->stats;
+ }
+
+ /**
+ * <code>.grpc.testing.ClientStats stats = 1;</code>
+ */
+ public function setStats(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ClientStats::class);
+ $this->stats = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php
new file mode 100644
index 0000000000..4f59da992f
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php
@@ -0,0 +1,34 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+/**
+ * Protobuf enum <code>grpc.testing.ClientType</code>
+ */
+class ClientType
+{
+ /**
+ * <pre>
+ * Many languages support a basic distinction between using
+ * sync or async client, and this allows the specification
+ * </pre>
+ *
+ * <code>SYNC_CLIENT = 0;</code>
+ */
+ const SYNC_CLIENT = 0;
+ /**
+ * <code>ASYNC_CLIENT = 1;</code>
+ */
+ const ASYNC_CLIENT = 1;
+ /**
+ * <pre>
+ * used for some language-specific variants
+ * </pre>
+ *
+ * <code>OTHER_CLIENT = 2;</code>
+ */
+ const OTHER_CLIENT = 2;
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php
new file mode 100644
index 0000000000..53f2948af2
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php
@@ -0,0 +1,28 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Once an RPC finishes, immediately start a new one.
+ * No configuration parameters needed.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ClosedLoopParams</code>
+ */
+class ClosedLoopParams extends \Google\Protobuf\Internal\Message
+{
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php
new file mode 100644
index 0000000000..6d990f1b06
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php
@@ -0,0 +1,28 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * TODO (vpai): Fill this in once the details of complex, representative
+ * protos are decided
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ComplexProtoParams</code>
+ */
+class ComplexProtoParams extends \Google\Protobuf\Internal\Message
+{
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
+ parent::__construct();
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php
new file mode 100644
index 0000000000..2e078b3fcd
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php
@@ -0,0 +1,23 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.CoreRequest</code>
+ */
+class CoreRequest extends \Google\Protobuf\Internal\Message
+{
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php
new file mode 100644
index 0000000000..85cb3418ad
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php
@@ -0,0 +1,56 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.CoreResponse</code>
+ */
+class CoreResponse extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Number of cores available on the server
+ * </pre>
+ *
+ * <code>int32 cores = 1;</code>
+ */
+ private $cores = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Number of cores available on the server
+ * </pre>
+ *
+ * <code>int32 cores = 1;</code>
+ */
+ public function getCores()
+ {
+ return $this->cores;
+ }
+
+ /**
+ * <pre>
+ * Number of cores available on the server
+ * </pre>
+ *
+ * <code>int32 cores = 1;</code>
+ */
+ public function setCores($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->cores = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php
new file mode 100644
index 0000000000..27340fb0ef
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php
@@ -0,0 +1,70 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * A protobuf representation for grpc status. This is used by test
+ * clients to specify a status that the server should attempt to return.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.EchoStatus</code>
+ */
+class EchoStatus extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>int32 code = 1;</code>
+ */
+ private $code = 0;
+ /**
+ * <code>string message = 2;</code>
+ */
+ private $message = '';
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>int32 code = 1;</code>
+ */
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+ /**
+ * <code>int32 code = 1;</code>
+ */
+ public function setCode($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->code = $var;
+ }
+
+ /**
+ * <code>string message = 2;</code>
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * <code>string message = 2;</code>
+ */
+ public function setMessage($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->message = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php
new file mode 100644
index 0000000000..056da6e5de
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php
@@ -0,0 +1,153 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Histogram data based on grpc/support/histogram.c
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.HistogramData</code>
+ */
+class HistogramData extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>repeated uint32 bucket = 1;</code>
+ */
+ private $bucket;
+ /**
+ * <code>double min_seen = 2;</code>
+ */
+ private $min_seen = 0.0;
+ /**
+ * <code>double max_seen = 3;</code>
+ */
+ private $max_seen = 0.0;
+ /**
+ * <code>double sum = 4;</code>
+ */
+ private $sum = 0.0;
+ /**
+ * <code>double sum_of_squares = 5;</code>
+ */
+ private $sum_of_squares = 0.0;
+ /**
+ * <code>double count = 6;</code>
+ */
+ private $count = 0.0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>repeated uint32 bucket = 1;</code>
+ */
+ public function getBucket()
+ {
+ return $this->bucket;
+ }
+
+ /**
+ * <code>repeated uint32 bucket = 1;</code>
+ */
+ public function setBucket(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::UINT32);
+ $this->bucket = $var;
+ }
+
+ /**
+ * <code>double min_seen = 2;</code>
+ */
+ public function getMinSeen()
+ {
+ return $this->min_seen;
+ }
+
+ /**
+ * <code>double min_seen = 2;</code>
+ */
+ public function setMinSeen($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->min_seen = $var;
+ }
+
+ /**
+ * <code>double max_seen = 3;</code>
+ */
+ public function getMaxSeen()
+ {
+ return $this->max_seen;
+ }
+
+ /**
+ * <code>double max_seen = 3;</code>
+ */
+ public function setMaxSeen($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->max_seen = $var;
+ }
+
+ /**
+ * <code>double sum = 4;</code>
+ */
+ public function getSum()
+ {
+ return $this->sum;
+ }
+
+ /**
+ * <code>double sum = 4;</code>
+ */
+ public function setSum($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->sum = $var;
+ }
+
+ /**
+ * <code>double sum_of_squares = 5;</code>
+ */
+ public function getSumOfSquares()
+ {
+ return $this->sum_of_squares;
+ }
+
+ /**
+ * <code>double sum_of_squares = 5;</code>
+ */
+ public function setSumOfSquares($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->sum_of_squares = $var;
+ }
+
+ /**
+ * <code>double count = 6;</code>
+ */
+ public function getCount()
+ {
+ return $this->count;
+ }
+
+ /**
+ * <code>double count = 6;</code>
+ */
+ public function setCount($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->count = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php
new file mode 100644
index 0000000000..836c94b01d
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php
@@ -0,0 +1,93 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Histogram params based on grpc/support/histogram.c
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.HistogramParams</code>
+ */
+class HistogramParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * first bucket is [0, 1 + resolution)
+ * </pre>
+ *
+ * <code>double resolution = 1;</code>
+ */
+ private $resolution = 0.0;
+ /**
+ * <pre>
+ * use enough buckets to allow this value
+ * </pre>
+ *
+ * <code>double max_possible = 2;</code>
+ */
+ private $max_possible = 0.0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * first bucket is [0, 1 + resolution)
+ * </pre>
+ *
+ * <code>double resolution = 1;</code>
+ */
+ public function getResolution()
+ {
+ return $this->resolution;
+ }
+
+ /**
+ * <pre>
+ * first bucket is [0, 1 + resolution)
+ * </pre>
+ *
+ * <code>double resolution = 1;</code>
+ */
+ public function setResolution($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->resolution = $var;
+ }
+
+ /**
+ * <pre>
+ * use enough buckets to allow this value
+ * </pre>
+ *
+ * <code>double max_possible = 2;</code>
+ */
+ public function getMaxPossible()
+ {
+ return $this->max_possible;
+ }
+
+ /**
+ * <pre>
+ * use enough buckets to allow this value
+ * </pre>
+ *
+ * <code>double max_possible = 2;</code>
+ */
+ public function setMaxPossible($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->max_possible = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php
new file mode 100644
index 0000000000..1f32e49c8a
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php
@@ -0,0 +1,63 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.LoadParams</code>
+ */
+class LoadParams extends \Google\Protobuf\Internal\Message
+{
+ protected $load;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+ */
+ public function getClosedLoop()
+ {
+ return $this->readOneof(1);
+ }
+
+ /**
+ * <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+ */
+ public function setClosedLoop(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ClosedLoopParams::class);
+ $this->writeOneof(1, $var);
+ }
+
+ /**
+ * <code>.grpc.testing.PoissonParams poisson = 2;</code>
+ */
+ public function getPoisson()
+ {
+ return $this->readOneof(2);
+ }
+
+ /**
+ * <code>.grpc.testing.PoissonParams poisson = 2;</code>
+ */
+ public function setPoisson(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\PoissonParams::class);
+ $this->writeOneof(2, $var);
+ }
+
+ public function getLoad()
+ {
+ return $this->whichOneof("load");
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php b/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php
new file mode 100644
index 0000000000..ce006efacd
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php
@@ -0,0 +1,60 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Request current stats
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.Mark</code>
+ */
+class Mark extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * if true, the stats will be reset after taking their snapshot.
+ * </pre>
+ *
+ * <code>bool reset = 1;</code>
+ */
+ private $reset = false;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * if true, the stats will be reset after taking their snapshot.
+ * </pre>
+ *
+ * <code>bool reset = 1;</code>
+ */
+ public function getReset()
+ {
+ return $this->reset;
+ }
+
+ /**
+ * <pre>
+ * if true, the stats will be reset after taking their snapshot.
+ * </pre>
+ *
+ * <code>bool reset = 1;</code>
+ */
+ public function setReset($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->reset = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php b/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php
new file mode 100644
index 0000000000..d17c271af7
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php
@@ -0,0 +1,96 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * A block of data, to simply increase gRPC message size.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.Payload</code>
+ */
+class Payload extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * The type of data in body.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType type = 1;</code>
+ */
+ private $type = 0;
+ /**
+ * <pre>
+ * Primary contents of payload.
+ * </pre>
+ *
+ * <code>bytes body = 2;</code>
+ */
+ private $body = '';
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * The type of data in body.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType type = 1;</code>
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * The type of data in body.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType type = 1;</code>
+ */
+ public function setType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
+ $this->type = $var;
+ }
+
+ /**
+ * <pre>
+ * Primary contents of payload.
+ * </pre>
+ *
+ * <code>bytes body = 2;</code>
+ */
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ /**
+ * <pre>
+ * Primary contents of payload.
+ * </pre>
+ *
+ * <code>bytes body = 2;</code>
+ */
+ public function setBody($var)
+ {
+ GPBUtil::checkString($var, False);
+ $this->body = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php
new file mode 100644
index 0000000000..a2fe7109ba
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php
@@ -0,0 +1,80 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.PayloadConfig</code>
+ */
+class PayloadConfig extends \Google\Protobuf\Internal\Message
+{
+ protected $payload;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+ */
+ public function getBytebufParams()
+ {
+ return $this->readOneof(1);
+ }
+
+ /**
+ * <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+ */
+ public function setBytebufParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ByteBufferParams::class);
+ $this->writeOneof(1, $var);
+ }
+
+ /**
+ * <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+ */
+ public function getSimpleParams()
+ {
+ return $this->readOneof(2);
+ }
+
+ /**
+ * <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+ */
+ public function setSimpleParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\SimpleProtoParams::class);
+ $this->writeOneof(2, $var);
+ }
+
+ /**
+ * <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+ */
+ public function getComplexParams()
+ {
+ return $this->readOneof(3);
+ }
+
+ /**
+ * <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+ */
+ public function setComplexParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ComplexProtoParams::class);
+ $this->writeOneof(3, $var);
+ }
+
+ public function getPayload()
+ {
+ return $this->whichOneof("payload");
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php
new file mode 100644
index 0000000000..189ef034b4
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php
@@ -0,0 +1,26 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+/**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * The type of payload that should be returned.
+ * </pre>
+ *
+ * Protobuf enum <code>grpc.testing.PayloadType</code>
+ */
+class PayloadType
+{
+ /**
+ * <pre>
+ * Compressable text format.
+ * </pre>
+ *
+ * <code>COMPRESSABLE = 0;</code>
+ */
+ const COMPRESSABLE = 0;
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php
new file mode 100644
index 0000000000..d64edd45f0
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php
@@ -0,0 +1,61 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Parameters of poisson process distribution, which is a good representation
+ * of activity coming in from independent identical stationary sources.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.PoissonParams</code>
+ */
+class PoissonParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
+ * </pre>
+ *
+ * <code>double offered_load = 1;</code>
+ */
+ private $offered_load = 0.0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
+ * </pre>
+ *
+ * <code>double offered_load = 1;</code>
+ */
+ public function getOfferedLoad()
+ {
+ return $this->offered_load;
+ }
+
+ /**
+ * <pre>
+ * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
+ * </pre>
+ *
+ * <code>double offered_load = 1;</code>
+ */
+ public function setOfferedLoad($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->offered_load = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php
new file mode 100644
index 0000000000..23c041b470
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php
@@ -0,0 +1,72 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2017, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+namespace Grpc\Testing {
+
+ class ProxyClientServiceClient extends \Grpc\BaseStub {
+
+ /**
+ * @param string $hostname hostname
+ * @param array $opts channel options
+ * @param Grpc\Channel $channel (optional) re-use channel object
+ */
+ public function __construct($hostname, $opts, $channel = null) {
+ parent::__construct($hostname, $opts, $channel);
+ }
+
+ /**
+ * @param \Grpc\Testing\Void $argument input argument
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function GetConfig(\Grpc\Testing\Void $argument,
+ $metadata = [], $options = []) {
+ return $this->_simpleRequest('/grpc.testing.ProxyClientService/GetConfig',
+ $argument,
+ ['\Grpc\Testing\ClientConfig', 'decode'],
+ $metadata, $options);
+ }
+
+ /**
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function ReportTime($metadata = [], $options = []) {
+ return $this->_clientStreamRequest('/grpc.testing.ProxyClientService/ReportTime',
+ ['\Grpc\Testing\Void','decode'],
+ $metadata, $options);
+ }
+
+ }
+
+}
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php
new file mode 100644
index 0000000000..ed43be99ce
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php
@@ -0,0 +1,44 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/proxy-service.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ProxyStat</code>
+ */
+class ProxyStat extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>double latency = 1;</code>
+ */
+ private $latency = 0.0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\ProxyService::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>double latency = 1;</code>
+ */
+ public function getLatency()
+ {
+ return $this->latency;
+ }
+
+ /**
+ * <code>double latency = 1;</code>
+ */
+ public function setLatency($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php
new file mode 100644
index 0000000000..dfaaa606c3
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php
@@ -0,0 +1,71 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * For reconnect interop test only.
+ * Server tells client whether its reconnects are following the spec and the
+ * reconnect backoffs it saw.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ReconnectInfo</code>
+ */
+class ReconnectInfo extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>bool passed = 1;</code>
+ */
+ private $passed = false;
+ /**
+ * <code>repeated int32 backoff_ms = 2;</code>
+ */
+ private $backoff_ms;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>bool passed = 1;</code>
+ */
+ public function getPassed()
+ {
+ return $this->passed;
+ }
+
+ /**
+ * <code>bool passed = 1;</code>
+ */
+ public function setPassed($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->passed = $var;
+ }
+
+ /**
+ * <code>repeated int32 backoff_ms = 2;</code>
+ */
+ public function getBackoffMs()
+ {
+ return $this->backoff_ms;
+ }
+
+ /**
+ * <code>repeated int32 backoff_ms = 2;</code>
+ */
+ public function setBackoffMs(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+ $this->backoff_ms = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php
new file mode 100644
index 0000000000..9715855783
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php
@@ -0,0 +1,49 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * For reconnect interop test only.
+ * Client tells server what reconnection parameters it used.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ReconnectParams</code>
+ */
+class ReconnectParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>int32 max_reconnect_backoff_ms = 1;</code>
+ */
+ private $max_reconnect_backoff_ms = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>int32 max_reconnect_backoff_ms = 1;</code>
+ */
+ public function getMaxReconnectBackoffMs()
+ {
+ return $this->max_reconnect_backoff_ms;
+ }
+
+ /**
+ * <code>int32 max_reconnect_backoff_ms = 1;</code>
+ */
+ public function setMaxReconnectBackoffMs($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->max_reconnect_backoff_ms = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php b/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php
new file mode 100644
index 0000000000..1be42b2ac9
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php
@@ -0,0 +1,65 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.RequestResultCount</code>
+ */
+class RequestResultCount extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>int32 status_code = 1;</code>
+ */
+ private $status_code = 0;
+ /**
+ * <code>int64 count = 2;</code>
+ */
+ private $count = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>int32 status_code = 1;</code>
+ */
+ public function getStatusCode()
+ {
+ return $this->status_code;
+ }
+
+ /**
+ * <code>int32 status_code = 1;</code>
+ */
+ public function setStatusCode($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->status_code = $var;
+ }
+
+ /**
+ * <code>int64 count = 2;</code>
+ */
+ public function getCount()
+ {
+ return $this->count;
+ }
+
+ /**
+ * <code>int64 count = 2;</code>
+ */
+ public function setCount($var)
+ {
+ GPBUtil::checkInt64($var);
+ $this->count = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php b/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php
new file mode 100644
index 0000000000..b7a8e5ece7
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php
@@ -0,0 +1,138 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Configuration for a particular response.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ResponseParameters</code>
+ */
+class ResponseParameters extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Desired payload sizes in responses from the server.
+ * </pre>
+ *
+ * <code>int32 size = 1;</code>
+ */
+ private $size = 0;
+ /**
+ * <pre>
+ * Desired interval between consecutive responses in the response stream in
+ * microseconds.
+ * </pre>
+ *
+ * <code>int32 interval_us = 2;</code>
+ */
+ private $interval_us = 0;
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue compressed = 3;</code>
+ */
+ private $compressed = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Desired payload sizes in responses from the server.
+ * </pre>
+ *
+ * <code>int32 size = 1;</code>
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * <pre>
+ * Desired payload sizes in responses from the server.
+ * </pre>
+ *
+ * <code>int32 size = 1;</code>
+ */
+ public function setSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->size = $var;
+ }
+
+ /**
+ * <pre>
+ * Desired interval between consecutive responses in the response stream in
+ * microseconds.
+ * </pre>
+ *
+ * <code>int32 interval_us = 2;</code>
+ */
+ public function getIntervalUs()
+ {
+ return $this->interval_us;
+ }
+
+ /**
+ * <pre>
+ * Desired interval between consecutive responses in the response stream in
+ * microseconds.
+ * </pre>
+ *
+ * <code>int32 interval_us = 2;</code>
+ */
+ public function setIntervalUs($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->interval_us = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue compressed = 3;</code>
+ */
+ public function getCompressed()
+ {
+ return $this->compressed;
+ }
+
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue compressed = 3;</code>
+ */
+ public function setCompressed(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
+ $this->compressed = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php b/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php
new file mode 100644
index 0000000000..2e664fff47
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php
@@ -0,0 +1,21 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+/**
+ * Protobuf enum <code>grpc.testing.RpcType</code>
+ */
+class RpcType
+{
+ /**
+ * <code>UNARY = 0;</code>
+ */
+ const UNARY = 0;
+ /**
+ * <code>STREAMING = 1;</code>
+ */
+ const STREAMING = 1;
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php b/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php
new file mode 100644
index 0000000000..136ed299ea
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php
@@ -0,0 +1,291 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * A single performance scenario: input to qps_json_driver
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.Scenario</code>
+ */
+class Scenario extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Human readable name for this scenario
+ * </pre>
+ *
+ * <code>string name = 1;</code>
+ */
+ private $name = '';
+ /**
+ * <pre>
+ * Client configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+ */
+ private $client_config = null;
+ /**
+ * <pre>
+ * Number of clients to start for the test
+ * </pre>
+ *
+ * <code>int32 num_clients = 3;</code>
+ */
+ private $num_clients = 0;
+ /**
+ * <pre>
+ * Server configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+ */
+ private $server_config = null;
+ /**
+ * <pre>
+ * Number of servers to start for the test
+ * </pre>
+ *
+ * <code>int32 num_servers = 5;</code>
+ */
+ private $num_servers = 0;
+ /**
+ * <pre>
+ * Warmup period, in seconds
+ * </pre>
+ *
+ * <code>int32 warmup_seconds = 6;</code>
+ */
+ private $warmup_seconds = 0;
+ /**
+ * <pre>
+ * Benchmark time, in seconds
+ * </pre>
+ *
+ * <code>int32 benchmark_seconds = 7;</code>
+ */
+ private $benchmark_seconds = 0;
+ /**
+ * <pre>
+ * Number of workers to spawn locally (usually zero)
+ * </pre>
+ *
+ * <code>int32 spawn_local_worker_count = 8;</code>
+ */
+ private $spawn_local_worker_count = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Human readable name for this scenario
+ * </pre>
+ *
+ * <code>string name = 1;</code>
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * <pre>
+ * Human readable name for this scenario
+ * </pre>
+ *
+ * <code>string name = 1;</code>
+ */
+ public function setName($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->name = $var;
+ }
+
+ /**
+ * <pre>
+ * Client configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+ */
+ public function getClientConfig()
+ {
+ return $this->client_config;
+ }
+
+ /**
+ * <pre>
+ * Client configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+ */
+ public function setClientConfig(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ClientConfig::class);
+ $this->client_config = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of clients to start for the test
+ * </pre>
+ *
+ * <code>int32 num_clients = 3;</code>
+ */
+ public function getNumClients()
+ {
+ return $this->num_clients;
+ }
+
+ /**
+ * <pre>
+ * Number of clients to start for the test
+ * </pre>
+ *
+ * <code>int32 num_clients = 3;</code>
+ */
+ public function setNumClients($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->num_clients = $var;
+ }
+
+ /**
+ * <pre>
+ * Server configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+ */
+ public function getServerConfig()
+ {
+ return $this->server_config;
+ }
+
+ /**
+ * <pre>
+ * Server configuration
+ * </pre>
+ *
+ * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+ */
+ public function setServerConfig(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ServerConfig::class);
+ $this->server_config = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of servers to start for the test
+ * </pre>
+ *
+ * <code>int32 num_servers = 5;</code>
+ */
+ public function getNumServers()
+ {
+ return $this->num_servers;
+ }
+
+ /**
+ * <pre>
+ * Number of servers to start for the test
+ * </pre>
+ *
+ * <code>int32 num_servers = 5;</code>
+ */
+ public function setNumServers($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->num_servers = $var;
+ }
+
+ /**
+ * <pre>
+ * Warmup period, in seconds
+ * </pre>
+ *
+ * <code>int32 warmup_seconds = 6;</code>
+ */
+ public function getWarmupSeconds()
+ {
+ return $this->warmup_seconds;
+ }
+
+ /**
+ * <pre>
+ * Warmup period, in seconds
+ * </pre>
+ *
+ * <code>int32 warmup_seconds = 6;</code>
+ */
+ public function setWarmupSeconds($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->warmup_seconds = $var;
+ }
+
+ /**
+ * <pre>
+ * Benchmark time, in seconds
+ * </pre>
+ *
+ * <code>int32 benchmark_seconds = 7;</code>
+ */
+ public function getBenchmarkSeconds()
+ {
+ return $this->benchmark_seconds;
+ }
+
+ /**
+ * <pre>
+ * Benchmark time, in seconds
+ * </pre>
+ *
+ * <code>int32 benchmark_seconds = 7;</code>
+ */
+ public function setBenchmarkSeconds($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->benchmark_seconds = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of workers to spawn locally (usually zero)
+ * </pre>
+ *
+ * <code>int32 spawn_local_worker_count = 8;</code>
+ */
+ public function getSpawnLocalWorkerCount()
+ {
+ return $this->spawn_local_worker_count;
+ }
+
+ /**
+ * <pre>
+ * Number of workers to spawn locally (usually zero)
+ * </pre>
+ *
+ * <code>int32 spawn_local_worker_count = 8;</code>
+ */
+ public function setSpawnLocalWorkerCount($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->spawn_local_worker_count = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php
new file mode 100644
index 0000000000..809cd96244
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php
@@ -0,0 +1,312 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Results of a single benchmark scenario.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ScenarioResult</code>
+ */
+class ScenarioResult extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Inputs used to run the scenario.
+ * </pre>
+ *
+ * <code>.grpc.testing.Scenario scenario = 1;</code>
+ */
+ private $scenario = null;
+ /**
+ * <pre>
+ * Histograms from all clients merged into one histogram.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 2;</code>
+ */
+ private $latencies = null;
+ /**
+ * <pre>
+ * Client stats for each client
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+ */
+ private $client_stats;
+ /**
+ * <pre>
+ * Server stats for each server
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+ */
+ private $server_stats;
+ /**
+ * <pre>
+ * Number of cores available to each server
+ * </pre>
+ *
+ * <code>repeated int32 server_cores = 5;</code>
+ */
+ private $server_cores;
+ /**
+ * <pre>
+ * An after-the-fact computed summary
+ * </pre>
+ *
+ * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+ */
+ private $summary = null;
+ /**
+ * <pre>
+ * Information on success or failure of each worker
+ * </pre>
+ *
+ * <code>repeated bool client_success = 7;</code>
+ */
+ private $client_success;
+ /**
+ * <code>repeated bool server_success = 8;</code>
+ */
+ private $server_success;
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+ */
+ private $request_results;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Inputs used to run the scenario.
+ * </pre>
+ *
+ * <code>.grpc.testing.Scenario scenario = 1;</code>
+ */
+ public function getScenario()
+ {
+ return $this->scenario;
+ }
+
+ /**
+ * <pre>
+ * Inputs used to run the scenario.
+ * </pre>
+ *
+ * <code>.grpc.testing.Scenario scenario = 1;</code>
+ */
+ public function setScenario(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Scenario::class);
+ $this->scenario = $var;
+ }
+
+ /**
+ * <pre>
+ * Histograms from all clients merged into one histogram.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 2;</code>
+ */
+ public function getLatencies()
+ {
+ return $this->latencies;
+ }
+
+ /**
+ * <pre>
+ * Histograms from all clients merged into one histogram.
+ * </pre>
+ *
+ * <code>.grpc.testing.HistogramData latencies = 2;</code>
+ */
+ public function setLatencies(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\HistogramData::class);
+ $this->latencies = $var;
+ }
+
+ /**
+ * <pre>
+ * Client stats for each client
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+ */
+ public function getClientStats()
+ {
+ return $this->client_stats;
+ }
+
+ /**
+ * <pre>
+ * Client stats for each client
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+ */
+ public function setClientStats(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ClientStats::class);
+ $this->client_stats = $var;
+ }
+
+ /**
+ * <pre>
+ * Server stats for each server
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+ */
+ public function getServerStats()
+ {
+ return $this->server_stats;
+ }
+
+ /**
+ * <pre>
+ * Server stats for each server
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+ */
+ public function setServerStats(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ServerStats::class);
+ $this->server_stats = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of cores available to each server
+ * </pre>
+ *
+ * <code>repeated int32 server_cores = 5;</code>
+ */
+ public function getServerCores()
+ {
+ return $this->server_cores;
+ }
+
+ /**
+ * <pre>
+ * Number of cores available to each server
+ * </pre>
+ *
+ * <code>repeated int32 server_cores = 5;</code>
+ */
+ public function setServerCores(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+ $this->server_cores = $var;
+ }
+
+ /**
+ * <pre>
+ * An after-the-fact computed summary
+ * </pre>
+ *
+ * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+ */
+ public function getSummary()
+ {
+ return $this->summary;
+ }
+
+ /**
+ * <pre>
+ * An after-the-fact computed summary
+ * </pre>
+ *
+ * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+ */
+ public function setSummary(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ScenarioResultSummary::class);
+ $this->summary = $var;
+ }
+
+ /**
+ * <pre>
+ * Information on success or failure of each worker
+ * </pre>
+ *
+ * <code>repeated bool client_success = 7;</code>
+ */
+ public function getClientSuccess()
+ {
+ return $this->client_success;
+ }
+
+ /**
+ * <pre>
+ * Information on success or failure of each worker
+ * </pre>
+ *
+ * <code>repeated bool client_success = 7;</code>
+ */
+ public function setClientSuccess(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
+ $this->client_success = $var;
+ }
+
+ /**
+ * <code>repeated bool server_success = 8;</code>
+ */
+ public function getServerSuccess()
+ {
+ return $this->server_success;
+ }
+
+ /**
+ * <code>repeated bool server_success = 8;</code>
+ */
+ public function setServerSuccess(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
+ $this->server_success = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+ */
+ public function getRequestResults()
+ {
+ return $this->request_results;
+ }
+
+ /**
+ * <pre>
+ * Number of failed requests (one row per status code seen)
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+ */
+ public function setRequestResults(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
+ $this->request_results = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php
new file mode 100644
index 0000000000..7520cff78e
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php
@@ -0,0 +1,430 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Basic summary that can be computed from ClientStats and ServerStats
+ * once the scenario has finished.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.ScenarioResultSummary</code>
+ */
+class ScenarioResultSummary extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Total number of operations per second over all clients.
+ * </pre>
+ *
+ * <code>double qps = 1;</code>
+ */
+ private $qps = 0.0;
+ /**
+ * <pre>
+ * QPS per one server core.
+ * </pre>
+ *
+ * <code>double qps_per_server_core = 2;</code>
+ */
+ private $qps_per_server_core = 0.0;
+ /**
+ * <pre>
+ * server load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_system_time = 3;</code>
+ */
+ private $server_system_time = 0.0;
+ /**
+ * <pre>
+ * server load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_user_time = 4;</code>
+ */
+ private $server_user_time = 0.0;
+ /**
+ * <pre>
+ * client load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_system_time = 5;</code>
+ */
+ private $client_system_time = 0.0;
+ /**
+ * <pre>
+ * client load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_user_time = 6;</code>
+ */
+ private $client_user_time = 0.0;
+ /**
+ * <pre>
+ * X% latency percentiles (in nanoseconds)
+ * </pre>
+ *
+ * <code>double latency_50 = 7;</code>
+ */
+ private $latency_50 = 0.0;
+ /**
+ * <code>double latency_90 = 8;</code>
+ */
+ private $latency_90 = 0.0;
+ /**
+ * <code>double latency_95 = 9;</code>
+ */
+ private $latency_95 = 0.0;
+ /**
+ * <code>double latency_99 = 10;</code>
+ */
+ private $latency_99 = 0.0;
+ /**
+ * <code>double latency_999 = 11;</code>
+ */
+ private $latency_999 = 0.0;
+ /**
+ * <pre>
+ * server cpu usage percentage
+ * </pre>
+ *
+ * <code>double server_cpu_usage = 12;</code>
+ */
+ private $server_cpu_usage = 0.0;
+ /**
+ * <pre>
+ * Number of requests that succeeded/failed
+ * </pre>
+ *
+ * <code>double successful_requests_per_second = 13;</code>
+ */
+ private $successful_requests_per_second = 0.0;
+ /**
+ * <code>double failed_requests_per_second = 14;</code>
+ */
+ private $failed_requests_per_second = 0.0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Total number of operations per second over all clients.
+ * </pre>
+ *
+ * <code>double qps = 1;</code>
+ */
+ public function getQps()
+ {
+ return $this->qps;
+ }
+
+ /**
+ * <pre>
+ * Total number of operations per second over all clients.
+ * </pre>
+ *
+ * <code>double qps = 1;</code>
+ */
+ public function setQps($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->qps = $var;
+ }
+
+ /**
+ * <pre>
+ * QPS per one server core.
+ * </pre>
+ *
+ * <code>double qps_per_server_core = 2;</code>
+ */
+ public function getQpsPerServerCore()
+ {
+ return $this->qps_per_server_core;
+ }
+
+ /**
+ * <pre>
+ * QPS per one server core.
+ * </pre>
+ *
+ * <code>double qps_per_server_core = 2;</code>
+ */
+ public function setQpsPerServerCore($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->qps_per_server_core = $var;
+ }
+
+ /**
+ * <pre>
+ * server load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_system_time = 3;</code>
+ */
+ public function getServerSystemTime()
+ {
+ return $this->server_system_time;
+ }
+
+ /**
+ * <pre>
+ * server load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_system_time = 3;</code>
+ */
+ public function setServerSystemTime($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->server_system_time = $var;
+ }
+
+ /**
+ * <pre>
+ * server load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_user_time = 4;</code>
+ */
+ public function getServerUserTime()
+ {
+ return $this->server_user_time;
+ }
+
+ /**
+ * <pre>
+ * server load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double server_user_time = 4;</code>
+ */
+ public function setServerUserTime($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->server_user_time = $var;
+ }
+
+ /**
+ * <pre>
+ * client load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_system_time = 5;</code>
+ */
+ public function getClientSystemTime()
+ {
+ return $this->client_system_time;
+ }
+
+ /**
+ * <pre>
+ * client load based on system_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_system_time = 5;</code>
+ */
+ public function setClientSystemTime($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->client_system_time = $var;
+ }
+
+ /**
+ * <pre>
+ * client load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_user_time = 6;</code>
+ */
+ public function getClientUserTime()
+ {
+ return $this->client_user_time;
+ }
+
+ /**
+ * <pre>
+ * client load based on user_time (0.85 =&gt; 85%)
+ * </pre>
+ *
+ * <code>double client_user_time = 6;</code>
+ */
+ public function setClientUserTime($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->client_user_time = $var;
+ }
+
+ /**
+ * <pre>
+ * X% latency percentiles (in nanoseconds)
+ * </pre>
+ *
+ * <code>double latency_50 = 7;</code>
+ */
+ public function getLatency50()
+ {
+ return $this->latency_50;
+ }
+
+ /**
+ * <pre>
+ * X% latency percentiles (in nanoseconds)
+ * </pre>
+ *
+ * <code>double latency_50 = 7;</code>
+ */
+ public function setLatency50($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency_50 = $var;
+ }
+
+ /**
+ * <code>double latency_90 = 8;</code>
+ */
+ public function getLatency90()
+ {
+ return $this->latency_90;
+ }
+
+ /**
+ * <code>double latency_90 = 8;</code>
+ */
+ public function setLatency90($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency_90 = $var;
+ }
+
+ /**
+ * <code>double latency_95 = 9;</code>
+ */
+ public function getLatency95()
+ {
+ return $this->latency_95;
+ }
+
+ /**
+ * <code>double latency_95 = 9;</code>
+ */
+ public function setLatency95($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency_95 = $var;
+ }
+
+ /**
+ * <code>double latency_99 = 10;</code>
+ */
+ public function getLatency99()
+ {
+ return $this->latency_99;
+ }
+
+ /**
+ * <code>double latency_99 = 10;</code>
+ */
+ public function setLatency99($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency_99 = $var;
+ }
+
+ /**
+ * <code>double latency_999 = 11;</code>
+ */
+ public function getLatency999()
+ {
+ return $this->latency_999;
+ }
+
+ /**
+ * <code>double latency_999 = 11;</code>
+ */
+ public function setLatency999($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->latency_999 = $var;
+ }
+
+ /**
+ * <pre>
+ * server cpu usage percentage
+ * </pre>
+ *
+ * <code>double server_cpu_usage = 12;</code>
+ */
+ public function getServerCpuUsage()
+ {
+ return $this->server_cpu_usage;
+ }
+
+ /**
+ * <pre>
+ * server cpu usage percentage
+ * </pre>
+ *
+ * <code>double server_cpu_usage = 12;</code>
+ */
+ public function setServerCpuUsage($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->server_cpu_usage = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of requests that succeeded/failed
+ * </pre>
+ *
+ * <code>double successful_requests_per_second = 13;</code>
+ */
+ public function getSuccessfulRequestsPerSecond()
+ {
+ return $this->successful_requests_per_second;
+ }
+
+ /**
+ * <pre>
+ * Number of requests that succeeded/failed
+ * </pre>
+ *
+ * <code>double successful_requests_per_second = 13;</code>
+ */
+ public function setSuccessfulRequestsPerSecond($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->successful_requests_per_second = $var;
+ }
+
+ /**
+ * <code>double failed_requests_per_second = 14;</code>
+ */
+ public function getFailedRequestsPerSecond()
+ {
+ return $this->failed_requests_per_second;
+ }
+
+ /**
+ * <code>double failed_requests_per_second = 14;</code>
+ */
+ public function setFailedRequestsPerSecond($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->failed_requests_per_second = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php b/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php
new file mode 100644
index 0000000000..278f555b76
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php
@@ -0,0 +1,48 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * A set of scenarios to be run with qps_json_driver
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.Scenarios</code>
+ */
+class Scenarios extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+ */
+ private $scenarios;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+ */
+ public function getScenarios()
+ {
+ return $this->scenarios;
+ }
+
+ /**
+ * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+ */
+ public function setScenarios(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\Scenario::class);
+ $this->scenarios = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php
new file mode 100644
index 0000000000..27a5b95cc9
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php
@@ -0,0 +1,69 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * presence of SecurityParams implies use of TLS
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.SecurityParams</code>
+ */
+class SecurityParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>bool use_test_ca = 1;</code>
+ */
+ private $use_test_ca = false;
+ /**
+ * <code>string server_host_override = 2;</code>
+ */
+ private $server_host_override = '';
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>bool use_test_ca = 1;</code>
+ */
+ public function getUseTestCa()
+ {
+ return $this->use_test_ca;
+ }
+
+ /**
+ * <code>bool use_test_ca = 1;</code>
+ */
+ public function setUseTestCa($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->use_test_ca = $var;
+ }
+
+ /**
+ * <code>string server_host_override = 2;</code>
+ */
+ public function getServerHostOverride()
+ {
+ return $this->server_host_override;
+ }
+
+ /**
+ * <code>string server_host_override = 2;</code>
+ */
+ public function setServerHostOverride($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->server_host_override = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php
new file mode 100644
index 0000000000..0d84b80124
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php
@@ -0,0 +1,63 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ServerArgs</code>
+ */
+class ServerArgs extends \Google\Protobuf\Internal\Message
+{
+ protected $argtype;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ServerConfig setup = 1;</code>
+ */
+ public function getSetup()
+ {
+ return $this->readOneof(1);
+ }
+
+ /**
+ * <code>.grpc.testing.ServerConfig setup = 1;</code>
+ */
+ public function setSetup(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ServerConfig::class);
+ $this->writeOneof(1, $var);
+ }
+
+ /**
+ * <code>.grpc.testing.Mark mark = 2;</code>
+ */
+ public function getMark()
+ {
+ return $this->readOneof(2);
+ }
+
+ /**
+ * <code>.grpc.testing.Mark mark = 2;</code>
+ */
+ public function setMark(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Mark::class);
+ $this->writeOneof(2, $var);
+ }
+
+ public function getArgtype()
+ {
+ return $this->whichOneof("argtype");
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php
new file mode 100644
index 0000000000..e2bcede48c
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php
@@ -0,0 +1,305 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ServerConfig</code>
+ */
+class ServerConfig extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>.grpc.testing.ServerType server_type = 1;</code>
+ */
+ private $server_type = 0;
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+ */
+ private $security_params = null;
+ /**
+ * <pre>
+ * Port on which to listen. Zero means pick unused port.
+ * </pre>
+ *
+ * <code>int32 port = 4;</code>
+ */
+ private $port = 0;
+ /**
+ * <pre>
+ * Only for async server. Number of threads used to serve the requests.
+ * </pre>
+ *
+ * <code>int32 async_server_threads = 7;</code>
+ */
+ private $async_server_threads = 0;
+ /**
+ * <pre>
+ * Specify the number of cores to limit server to, if desired
+ * </pre>
+ *
+ * <code>int32 core_limit = 8;</code>
+ */
+ private $core_limit = 0;
+ /**
+ * <pre>
+ * payload config, used in generic server.
+ * Note this must NOT be used in proto (non-generic) servers. For proto servers,
+ * 'response sizes' must be configured from the 'response_size' field of the
+ * 'SimpleRequest' objects in RPC requests.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+ */
+ private $payload_config = null;
+ /**
+ * <pre>
+ * Specify the cores we should run the server on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 10;</code>
+ */
+ private $core_list;
+ /**
+ * <pre>
+ * If we use an OTHER_SERVER client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_server_api = 11;</code>
+ */
+ private $other_server_api = '';
+ /**
+ * <pre>
+ * Buffer pool size (no buffer pool specified if unset)
+ * </pre>
+ *
+ * <code>int32 resource_quota_size = 1001;</code>
+ */
+ private $resource_quota_size = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ServerType server_type = 1;</code>
+ */
+ public function getServerType()
+ {
+ return $this->server_type;
+ }
+
+ /**
+ * <code>.grpc.testing.ServerType server_type = 1;</code>
+ */
+ public function setServerType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\ServerType::class);
+ $this->server_type = $var;
+ }
+
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+ */
+ public function getSecurityParams()
+ {
+ return $this->security_params;
+ }
+
+ /**
+ * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+ */
+ public function setSecurityParams(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\SecurityParams::class);
+ $this->security_params = $var;
+ }
+
+ /**
+ * <pre>
+ * Port on which to listen. Zero means pick unused port.
+ * </pre>
+ *
+ * <code>int32 port = 4;</code>
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * <pre>
+ * Port on which to listen. Zero means pick unused port.
+ * </pre>
+ *
+ * <code>int32 port = 4;</code>
+ */
+ public function setPort($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->port = $var;
+ }
+
+ /**
+ * <pre>
+ * Only for async server. Number of threads used to serve the requests.
+ * </pre>
+ *
+ * <code>int32 async_server_threads = 7;</code>
+ */
+ public function getAsyncServerThreads()
+ {
+ return $this->async_server_threads;
+ }
+
+ /**
+ * <pre>
+ * Only for async server. Number of threads used to serve the requests.
+ * </pre>
+ *
+ * <code>int32 async_server_threads = 7;</code>
+ */
+ public function setAsyncServerThreads($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->async_server_threads = $var;
+ }
+
+ /**
+ * <pre>
+ * Specify the number of cores to limit server to, if desired
+ * </pre>
+ *
+ * <code>int32 core_limit = 8;</code>
+ */
+ public function getCoreLimit()
+ {
+ return $this->core_limit;
+ }
+
+ /**
+ * <pre>
+ * Specify the number of cores to limit server to, if desired
+ * </pre>
+ *
+ * <code>int32 core_limit = 8;</code>
+ */
+ public function setCoreLimit($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->core_limit = $var;
+ }
+
+ /**
+ * <pre>
+ * payload config, used in generic server.
+ * Note this must NOT be used in proto (non-generic) servers. For proto servers,
+ * 'response sizes' must be configured from the 'response_size' field of the
+ * 'SimpleRequest' objects in RPC requests.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+ */
+ public function getPayloadConfig()
+ {
+ return $this->payload_config;
+ }
+
+ /**
+ * <pre>
+ * payload config, used in generic server.
+ * Note this must NOT be used in proto (non-generic) servers. For proto servers,
+ * 'response sizes' must be configured from the 'response_size' field of the
+ * 'SimpleRequest' objects in RPC requests.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+ */
+ public function setPayloadConfig(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\PayloadConfig::class);
+ $this->payload_config = $var;
+ }
+
+ /**
+ * <pre>
+ * Specify the cores we should run the server on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 10;</code>
+ */
+ public function getCoreList()
+ {
+ return $this->core_list;
+ }
+
+ /**
+ * <pre>
+ * Specify the cores we should run the server on, if desired
+ * </pre>
+ *
+ * <code>repeated int32 core_list = 10;</code>
+ */
+ public function setCoreList(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+ $this->core_list = $var;
+ }
+
+ /**
+ * <pre>
+ * If we use an OTHER_SERVER client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_server_api = 11;</code>
+ */
+ public function getOtherServerApi()
+ {
+ return $this->other_server_api;
+ }
+
+ /**
+ * <pre>
+ * If we use an OTHER_SERVER client_type, this string gives more detail
+ * </pre>
+ *
+ * <code>string other_server_api = 11;</code>
+ */
+ public function setOtherServerApi($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->other_server_api = $var;
+ }
+
+ /**
+ * <pre>
+ * Buffer pool size (no buffer pool specified if unset)
+ * </pre>
+ *
+ * <code>int32 resource_quota_size = 1001;</code>
+ */
+ public function getResourceQuotaSize()
+ {
+ return $this->resource_quota_size;
+ }
+
+ /**
+ * <pre>
+ * Buffer pool size (no buffer pool specified if unset)
+ * </pre>
+ *
+ * <code>int32 resource_quota_size = 1001;</code>
+ */
+ public function setResourceQuotaSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->resource_quota_size = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php
new file mode 100644
index 0000000000..98b2af764c
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php
@@ -0,0 +1,191 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ServerStats</code>
+ */
+class ServerStats extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * wall clock time change in seconds since last reset
+ * </pre>
+ *
+ * <code>double time_elapsed = 1;</code>
+ */
+ private $time_elapsed = 0.0;
+ /**
+ * <pre>
+ * change in user time (in seconds) used by the server since last reset
+ * </pre>
+ *
+ * <code>double time_user = 2;</code>
+ */
+ private $time_user = 0.0;
+ /**
+ * <pre>
+ * change in server time (in seconds) used by the server process and all
+ * threads since last reset
+ * </pre>
+ *
+ * <code>double time_system = 3;</code>
+ */
+ private $time_system = 0.0;
+ /**
+ * <pre>
+ * change in total cpu time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 total_cpu_time = 4;</code>
+ */
+ private $total_cpu_time = 0;
+ /**
+ * <pre>
+ * change in idle time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 idle_cpu_time = 5;</code>
+ */
+ private $idle_cpu_time = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * wall clock time change in seconds since last reset
+ * </pre>
+ *
+ * <code>double time_elapsed = 1;</code>
+ */
+ public function getTimeElapsed()
+ {
+ return $this->time_elapsed;
+ }
+
+ /**
+ * <pre>
+ * wall clock time change in seconds since last reset
+ * </pre>
+ *
+ * <code>double time_elapsed = 1;</code>
+ */
+ public function setTimeElapsed($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_elapsed = $var;
+ }
+
+ /**
+ * <pre>
+ * change in user time (in seconds) used by the server since last reset
+ * </pre>
+ *
+ * <code>double time_user = 2;</code>
+ */
+ public function getTimeUser()
+ {
+ return $this->time_user;
+ }
+
+ /**
+ * <pre>
+ * change in user time (in seconds) used by the server since last reset
+ * </pre>
+ *
+ * <code>double time_user = 2;</code>
+ */
+ public function setTimeUser($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_user = $var;
+ }
+
+ /**
+ * <pre>
+ * change in server time (in seconds) used by the server process and all
+ * threads since last reset
+ * </pre>
+ *
+ * <code>double time_system = 3;</code>
+ */
+ public function getTimeSystem()
+ {
+ return $this->time_system;
+ }
+
+ /**
+ * <pre>
+ * change in server time (in seconds) used by the server process and all
+ * threads since last reset
+ * </pre>
+ *
+ * <code>double time_system = 3;</code>
+ */
+ public function setTimeSystem($var)
+ {
+ GPBUtil::checkDouble($var);
+ $this->time_system = $var;
+ }
+
+ /**
+ * <pre>
+ * change in total cpu time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 total_cpu_time = 4;</code>
+ */
+ public function getTotalCpuTime()
+ {
+ return $this->total_cpu_time;
+ }
+
+ /**
+ * <pre>
+ * change in total cpu time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 total_cpu_time = 4;</code>
+ */
+ public function setTotalCpuTime($var)
+ {
+ GPBUtil::checkUint64($var);
+ $this->total_cpu_time = $var;
+ }
+
+ /**
+ * <pre>
+ * change in idle time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 idle_cpu_time = 5;</code>
+ */
+ public function getIdleCpuTime()
+ {
+ return $this->idle_cpu_time;
+ }
+
+ /**
+ * <pre>
+ * change in idle time of the server (data from proc/stat)
+ * </pre>
+ *
+ * <code>uint64 idle_cpu_time = 5;</code>
+ */
+ public function setIdleCpuTime($var)
+ {
+ GPBUtil::checkUint64($var);
+ $this->idle_cpu_time = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php
new file mode 100644
index 0000000000..d293f03fbd
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php
@@ -0,0 +1,110 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.ServerStatus</code>
+ */
+class ServerStatus extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>.grpc.testing.ServerStats stats = 1;</code>
+ */
+ private $stats = null;
+ /**
+ * <pre>
+ * the port bound by the server
+ * </pre>
+ *
+ * <code>int32 port = 2;</code>
+ */
+ private $port = 0;
+ /**
+ * <pre>
+ * Number of cores available to the server
+ * </pre>
+ *
+ * <code>int32 cores = 3;</code>
+ */
+ private $cores = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>.grpc.testing.ServerStats stats = 1;</code>
+ */
+ public function getStats()
+ {
+ return $this->stats;
+ }
+
+ /**
+ * <code>.grpc.testing.ServerStats stats = 1;</code>
+ */
+ public function setStats(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\ServerStats::class);
+ $this->stats = $var;
+ }
+
+ /**
+ * <pre>
+ * the port bound by the server
+ * </pre>
+ *
+ * <code>int32 port = 2;</code>
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * <pre>
+ * the port bound by the server
+ * </pre>
+ *
+ * <code>int32 port = 2;</code>
+ */
+ public function setPort($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->port = $var;
+ }
+
+ /**
+ * <pre>
+ * Number of cores available to the server
+ * </pre>
+ *
+ * <code>int32 cores = 3;</code>
+ */
+ public function getCores()
+ {
+ return $this->cores;
+ }
+
+ /**
+ * <pre>
+ * Number of cores available to the server
+ * </pre>
+ *
+ * <code>int32 cores = 3;</code>
+ */
+ public function setCores($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->cores = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php
new file mode 100644
index 0000000000..605c83c3f7
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php
@@ -0,0 +1,33 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+/**
+ * Protobuf enum <code>grpc.testing.ServerType</code>
+ */
+class ServerType
+{
+ /**
+ * <code>SYNC_SERVER = 0;</code>
+ */
+ const SYNC_SERVER = 0;
+ /**
+ * <code>ASYNC_SERVER = 1;</code>
+ */
+ const ASYNC_SERVER = 1;
+ /**
+ * <code>ASYNC_GENERIC_SERVER = 2;</code>
+ */
+ const ASYNC_GENERIC_SERVER = 2;
+ /**
+ * <pre>
+ * used for some language-specific variants
+ * </pre>
+ *
+ * <code>OTHER_SERVER = 3;</code>
+ */
+ const OTHER_SERVER = 3;
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php
new file mode 100644
index 0000000000..29834a3be7
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php
@@ -0,0 +1,65 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.SimpleProtoParams</code>
+ */
+class SimpleProtoParams extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ private $req_size = 0;
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ private $resp_size = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ public function getReqSize()
+ {
+ return $this->req_size;
+ }
+
+ /**
+ * <code>int32 req_size = 1;</code>
+ */
+ public function setReqSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->req_size = $var;
+ }
+
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ public function getRespSize()
+ {
+ return $this->resp_size;
+ }
+
+ /**
+ * <code>int32 resp_size = 2;</code>
+ */
+ public function setRespSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->resp_size = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php
new file mode 100644
index 0000000000..f84c95319f
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php
@@ -0,0 +1,306 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Unary request.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.SimpleRequest</code>
+ */
+class SimpleRequest extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, server randomly chooses one from other formats.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ private $response_type = 0;
+ /**
+ * <pre>
+ * Desired payload size in the response from the server.
+ * </pre>
+ *
+ * <code>int32 response_size = 2;</code>
+ */
+ private $response_size = 0;
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ private $payload = null;
+ /**
+ * <pre>
+ * Whether SimpleResponse should include username.
+ * </pre>
+ *
+ * <code>bool fill_username = 4;</code>
+ */
+ private $fill_username = false;
+ /**
+ * <pre>
+ * Whether SimpleResponse should include OAuth scope.
+ * </pre>
+ *
+ * <code>bool fill_oauth_scope = 5;</code>
+ */
+ private $fill_oauth_scope = false;
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+ */
+ private $response_compressed = null;
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ private $response_status = null;
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+ */
+ private $expect_compressed = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, server randomly chooses one from other formats.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ public function getResponseType()
+ {
+ return $this->response_type;
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, server randomly chooses one from other formats.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ public function setResponseType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
+ $this->response_type = $var;
+ }
+
+ /**
+ * <pre>
+ * Desired payload size in the response from the server.
+ * </pre>
+ *
+ * <code>int32 response_size = 2;</code>
+ */
+ public function getResponseSize()
+ {
+ return $this->response_size;
+ }
+
+ /**
+ * <pre>
+ * Desired payload size in the response from the server.
+ * </pre>
+ *
+ * <code>int32 response_size = 2;</code>
+ */
+ public function setResponseSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->response_size = $var;
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ public function setPayload(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
+ $this->payload = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether SimpleResponse should include username.
+ * </pre>
+ *
+ * <code>bool fill_username = 4;</code>
+ */
+ public function getFillUsername()
+ {
+ return $this->fill_username;
+ }
+
+ /**
+ * <pre>
+ * Whether SimpleResponse should include username.
+ * </pre>
+ *
+ * <code>bool fill_username = 4;</code>
+ */
+ public function setFillUsername($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->fill_username = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether SimpleResponse should include OAuth scope.
+ * </pre>
+ *
+ * <code>bool fill_oauth_scope = 5;</code>
+ */
+ public function getFillOauthScope()
+ {
+ return $this->fill_oauth_scope;
+ }
+
+ /**
+ * <pre>
+ * Whether SimpleResponse should include OAuth scope.
+ * </pre>
+ *
+ * <code>bool fill_oauth_scope = 5;</code>
+ */
+ public function setFillOauthScope($var)
+ {
+ GPBUtil::checkBool($var);
+ $this->fill_oauth_scope = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+ */
+ public function getResponseCompressed()
+ {
+ return $this->response_compressed;
+ }
+
+ /**
+ * <pre>
+ * Whether to request the server to compress the response. This field is
+ * "nullable" in order to interoperate seamlessly with clients not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the response's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+ */
+ public function setResponseCompressed(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
+ $this->response_compressed = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ public function getResponseStatus()
+ {
+ return $this->response_status;
+ }
+
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ public function setResponseStatus(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\EchoStatus::class);
+ $this->response_status = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+ */
+ public function getExpectCompressed()
+ {
+ return $this->expect_compressed;
+ }
+
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+ */
+ public function setExpectCompressed(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
+ $this->expect_compressed = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php
new file mode 100644
index 0000000000..ccc628ec4c
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php
@@ -0,0 +1,129 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Unary response, as configured by the request.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.SimpleResponse</code>
+ */
+class SimpleResponse extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Payload to increase message size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ private $payload = null;
+ /**
+ * <pre>
+ * The user the request came from, for verifying authentication was
+ * successful when the client expected it.
+ * </pre>
+ *
+ * <code>string username = 2;</code>
+ */
+ private $username = '';
+ /**
+ * <pre>
+ * OAuth scope.
+ * </pre>
+ *
+ * <code>string oauth_scope = 3;</code>
+ */
+ private $oauth_scope = '';
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Payload to increase message size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * <pre>
+ * Payload to increase message size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function setPayload(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
+ $this->payload = $var;
+ }
+
+ /**
+ * <pre>
+ * The user the request came from, for verifying authentication was
+ * successful when the client expected it.
+ * </pre>
+ *
+ * <code>string username = 2;</code>
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * <pre>
+ * The user the request came from, for verifying authentication was
+ * successful when the client expected it.
+ * </pre>
+ *
+ * <code>string username = 2;</code>
+ */
+ public function setUsername($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->username = $var;
+ }
+
+ /**
+ * <pre>
+ * OAuth scope.
+ * </pre>
+ *
+ * <code>string oauth_scope = 3;</code>
+ */
+ public function getOauthScope()
+ {
+ return $this->oauth_scope;
+ }
+
+ /**
+ * <pre>
+ * OAuth scope.
+ * </pre>
+ *
+ * <code>string oauth_scope = 3;</code>
+ */
+ public function setOauthScope($var)
+ {
+ GPBUtil::checkString($var, True);
+ $this->oauth_scope = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php
new file mode 100644
index 0000000000..d7bbc70779
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php
@@ -0,0 +1,102 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Client-streaming request.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.StreamingInputCallRequest</code>
+ */
+class StreamingInputCallRequest extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ private $payload = null;
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed. This field
+ * is "nullable" in order to interoperate seamlessly with servers not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the request's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+ */
+ private $expect_compressed = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function setPayload(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
+ $this->payload = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed. This field
+ * is "nullable" in order to interoperate seamlessly with servers not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the request's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+ */
+ public function getExpectCompressed()
+ {
+ return $this->expect_compressed;
+ }
+
+ /**
+ * <pre>
+ * Whether the server should expect this request to be compressed. This field
+ * is "nullable" in order to interoperate seamlessly with servers not able to
+ * implement the full compression tests by introspecting the call to verify
+ * the request's compression status.
+ * </pre>
+ *
+ * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+ */
+ public function setExpectCompressed(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
+ $this->expect_compressed = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php
new file mode 100644
index 0000000000..fdd1d0dbf8
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php
@@ -0,0 +1,60 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Client-streaming response.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.StreamingInputCallResponse</code>
+ */
+class StreamingInputCallResponse extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Aggregated size of payloads received from the client.
+ * </pre>
+ *
+ * <code>int32 aggregated_payload_size = 1;</code>
+ */
+ private $aggregated_payload_size = 0;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Aggregated size of payloads received from the client.
+ * </pre>
+ *
+ * <code>int32 aggregated_payload_size = 1;</code>
+ */
+ public function getAggregatedPayloadSize()
+ {
+ return $this->aggregated_payload_size;
+ }
+
+ /**
+ * <pre>
+ * Aggregated size of payloads received from the client.
+ * </pre>
+ *
+ * <code>int32 aggregated_payload_size = 1;</code>
+ */
+ public function setAggregatedPayloadSize($var)
+ {
+ GPBUtil::checkInt32($var);
+ $this->aggregated_payload_size = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php
new file mode 100644
index 0000000000..2aab5fadad
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php
@@ -0,0 +1,171 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Server-streaming request.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.StreamingOutputCallRequest</code>
+ */
+class StreamingOutputCallRequest extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, the payload from each response in the stream
+ * might be of different types. This is to simulate a mixed type of payload
+ * stream.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ private $response_type = 0;
+ /**
+ * <pre>
+ * Configuration for each expected response message.
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+ */
+ private $response_parameters;
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ private $payload = null;
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ private $response_status = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, the payload from each response in the stream
+ * might be of different types. This is to simulate a mixed type of payload
+ * stream.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ public function getResponseType()
+ {
+ return $this->response_type;
+ }
+
+ /**
+ * <pre>
+ * DEPRECATED, don't use. To be removed shortly.
+ * Desired payload type in the response from the server.
+ * If response_type is RANDOM, the payload from each response in the stream
+ * might be of different types. This is to simulate a mixed type of payload
+ * stream.
+ * </pre>
+ *
+ * <code>.grpc.testing.PayloadType response_type = 1;</code>
+ */
+ public function setResponseType($var)
+ {
+ GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
+ $this->response_type = $var;
+ }
+
+ /**
+ * <pre>
+ * Configuration for each expected response message.
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+ */
+ public function getResponseParameters()
+ {
+ return $this->response_parameters;
+ }
+
+ /**
+ * <pre>
+ * Configuration for each expected response message.
+ * </pre>
+ *
+ * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+ */
+ public function setResponseParameters(&$var)
+ {
+ GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ResponseParameters::class);
+ $this->response_parameters = $var;
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * <pre>
+ * Optional input payload sent along with the request.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 3;</code>
+ */
+ public function setPayload(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
+ $this->payload = $var;
+ }
+
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ public function getResponseStatus()
+ {
+ return $this->response_status;
+ }
+
+ /**
+ * <pre>
+ * Whether server should return a given status
+ * </pre>
+ *
+ * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+ */
+ public function setResponseStatus(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\EchoStatus::class);
+ $this->response_status = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php
new file mode 100644
index 0000000000..c06c78c9d8
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php
@@ -0,0 +1,60 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * <pre>
+ * Server-streaming response, as configured by the request and parameters.
+ * </pre>
+ *
+ * Protobuf type <code>grpc.testing.StreamingOutputCallResponse</code>
+ */
+class StreamingOutputCallResponse extends \Google\Protobuf\Internal\Message
+{
+ /**
+ * <pre>
+ * Payload to increase response size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ private $payload = null;
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
+ parent::__construct();
+ }
+
+ /**
+ * <pre>
+ * Payload to increase response size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * <pre>
+ * Payload to increase response size.
+ * </pre>
+ *
+ * <code>.grpc.testing.Payload payload = 1;</code>
+ */
+ public function setPayload(&$var)
+ {
+ GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
+ $this->payload = $var;
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Void.php b/src/php/tests/qps/generated_code/Grpc/Testing/Void.php
new file mode 100644
index 0000000000..38c100845a
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Void.php
@@ -0,0 +1,23 @@
+<?php
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+namespace Grpc\Testing;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Protobuf type <code>grpc.testing.Void</code>
+ */
+class Void extends \Google\Protobuf\Internal\Message
+{
+
+ public function __construct() {
+ \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+ parent::__construct();
+ }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php
new file mode 100644
index 0000000000..0a68e41269
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php
@@ -0,0 +1,111 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// 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.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+namespace Grpc\Testing {
+
+ class WorkerServiceClient extends \Grpc\BaseStub {
+
+ /**
+ * @param string $hostname hostname
+ * @param array $opts channel options
+ * @param Grpc\Channel $channel (optional) re-use channel object
+ */
+ public function __construct($hostname, $opts, $channel = null) {
+ parent::__construct($hostname, $opts, $channel);
+ }
+
+ /**
+ * Start server with specified workload.
+ * First request sent specifies the ServerConfig followed by ServerStatus
+ * response. After that, a "Mark" can be sent anytime to request the latest
+ * stats. Closing the stream will initiate shutdown of the test server
+ * and once the shutdown has finished, the OK status is sent to terminate
+ * this RPC.
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function RunServer($metadata = [], $options = []) {
+ return $this->_bidiRequest('/grpc.testing.WorkerService/RunServer',
+ ['\Grpc\Testing\ServerStatus','decode'],
+ $metadata, $options);
+ }
+
+ /**
+ * Start client with specified workload.
+ * First request sent specifies the ClientConfig followed by ClientStatus
+ * response. After that, a "Mark" can be sent anytime to request the latest
+ * stats. Closing the stream will initiate shutdown of the test client
+ * and once the shutdown has finished, the OK status is sent to terminate
+ * this RPC.
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function RunClient($metadata = [], $options = []) {
+ return $this->_bidiRequest('/grpc.testing.WorkerService/RunClient',
+ ['\Grpc\Testing\ClientStatus','decode'],
+ $metadata, $options);
+ }
+
+ /**
+ * Just return the core count - unary call
+ * @param \Grpc\Testing\CoreRequest $argument input argument
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function CoreCount(\Grpc\Testing\CoreRequest $argument,
+ $metadata = [], $options = []) {
+ return $this->_simpleRequest('/grpc.testing.WorkerService/CoreCount',
+ $argument,
+ ['\Grpc\Testing\CoreResponse', 'decode'],
+ $metadata, $options);
+ }
+
+ /**
+ * Quit this worker
+ * @param \Grpc\Testing\Void $argument input argument
+ * @param array $metadata metadata
+ * @param array $options call options
+ */
+ public function QuitWorker(\Grpc\Testing\Void $argument,
+ $metadata = [], $options = []) {
+ return $this->_simpleRequest('/grpc.testing.WorkerService/QuitWorker',
+ $argument,
+ ['\Grpc\Testing\Void', 'decode'],
+ $metadata, $options);
+ }
+
+ }
+
+}
diff --git a/src/proto/grpc/testing/proxy-service.proto b/src/proto/grpc/testing/proxy-service.proto
new file mode 100644
index 0000000000..7b7de8d549
--- /dev/null
+++ b/src/proto/grpc/testing/proxy-service.proto
@@ -0,0 +1,44 @@
+// Copyright 2017, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+import "src/proto/grpc/testing/control.proto";
+
+package grpc.testing;
+
+message ProxyStat {
+ double latency = 1;
+}
+
+service ProxyClientService {
+ rpc GetConfig(Void) returns (ClientConfig);
+ rpc ReportTime(stream ProxyStat) returns (Void);
+}
+
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index a9f20e6d2a..5fc748483a 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -33,6 +33,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/profiling/basic_timers.c',
'src/core/lib/profiling/stap_timers.c',
'src/core/lib/support/alloc.c',
+ 'src/core/lib/support/arena.c',
'src/core/lib/support/avl.c',
'src/core/lib/support/backoff.c',
'src/core/lib/support/cmdline.c',
@@ -134,6 +135,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/tcp_client_windows.c',
'src/core/lib/iomgr/tcp_posix.c',
'src/core/lib/iomgr/tcp_server_posix.c',
+ 'src/core/lib/iomgr/tcp_server_utils_posix_common.c',
+ 'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c',
+ 'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c',
'src/core/lib/iomgr/tcp_server_uv.c',
'src/core/lib/iomgr/tcp_server_windows.c',
'src/core/lib/iomgr/tcp_uv.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index c197e92ca5..267d848e74 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION='1.2.0.dev0'
+VERSION='1.3.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_health/v1/health.py b/src/python/grpcio_health_checking/grpc_health/v1/health.py
index f0f11cf84b..e92c2659b7 100644
--- a/src/python/grpcio_health_checking/grpc_health/v1/health.py
+++ b/src/python/grpcio_health_checking/grpc_health/v1/health.py
@@ -33,9 +33,10 @@ import threading
import grpc
from grpc_health.v1 import health_pb2
+from grpc_health.v1 import health_pb2_grpc
-class HealthServicer(health_pb2.HealthServicer):
+class HealthServicer(health_pb2_grpc.HealthServicer):
"""Servicer handling RPCs for service statuses."""
def __init__(self):
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index c1807e9f1c..4ff5e266a1 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
-VERSION='1.2.0.dev0'
+VERSION='1.3.0.dev0'
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 3778dcd3e0..8ffc08c04b 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
-VERSION='1.2.0.dev0'
+VERSION='1.3.0.dev0'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 33824b6b8f..ba82dce6f6 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
-VERSION='1.2.0.dev0'
+VERSION='1.3.0.dev0'
diff --git a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
index 363b4c5f99..1bc8669dad 100644
--- a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
+++ b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
@@ -34,6 +34,7 @@ import grpc
from grpc.framework.foundation import logging_pool
from grpc_health.v1 import health
from grpc_health.v1 import health_pb2
+from grpc_health.v1 import health_pb2_grpc
from tests.unit.framework.common import test_constants
@@ -52,11 +53,11 @@ class HealthServicerTest(unittest.TestCase):
server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
self._server = grpc.server(server_pool)
port = self._server.add_insecure_port('[::]:0')
- health_pb2.add_HealthServicer_to_server(servicer, self._server)
+ health_pb2_grpc.add_HealthServicer_to_server(servicer, self._server)
self._server.start()
channel = grpc.insecure_channel('localhost:%d' % port)
- self._stub = health_pb2.HealthStub(channel)
+ self._stub = health_pb2_grpc.HealthStub(channel)
def test_empty_service(self):
request = health_pb2.HealthCheckRequest()
diff --git a/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
index 58f3b364ba..3325d54375 100644
--- a/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
@@ -32,7 +32,7 @@ from concurrent import futures
import unittest
import grpc
-from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import test_pb2_grpc
from tests.interop import _intraop_test_case
from tests.interop import methods
@@ -44,11 +44,11 @@ class InsecureIntraopTest(_intraop_test_case.IntraopTestCase,
def setUp(self):
self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
- test_pb2.add_TestServiceServicer_to_server(methods.TestService(),
- self.server)
+ test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(),
+ self.server)
port = self.server.add_insecure_port('[::]:0')
self.server.start()
- self.stub = test_pb2.TestServiceStub(
+ self.stub = test_pb2_grpc.TestServiceStub(
grpc.insecure_channel('localhost:{}'.format(port)))
diff --git a/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
index 5fe929b99e..857e00efb3 100644
--- a/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
@@ -32,7 +32,7 @@ from concurrent import futures
import unittest
import grpc
-from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import test_pb2_grpc
from tests.interop import _intraop_test_case
from tests.interop import methods
@@ -45,14 +45,14 @@ class SecureIntraopTest(_intraop_test_case.IntraopTestCase, unittest.TestCase):
def setUp(self):
self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
- test_pb2.add_TestServiceServicer_to_server(methods.TestService(),
- self.server)
+ test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(),
+ self.server)
port = self.server.add_secure_port(
'[::]:0',
grpc.ssl_server_credentials(
[(resources.private_key(), resources.certificate_chain())]))
self.server.start()
- self.stub = test_pb2.TestServiceStub(
+ self.stub = test_pb2_grpc.TestServiceStub(
grpc.secure_channel('localhost:{}'.format(port),
grpc.ssl_channel_credentials(
resources.test_root_certificates()), (
diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py
index 662ea9ce57..e1016f7c0d 100644
--- a/src/python/grpcio_tests/tests/interop/methods.py
+++ b/src/python/grpcio_tests/tests/interop/methods.py
@@ -40,7 +40,7 @@ from grpc.beta import implementations
from src.proto.grpc.testing import empty_pb2
from src.proto.grpc.testing import messages_pb2
-from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import test_pb2_grpc
_INITIAL_METADATA_KEY = "x-grpc-test-echo-initial"
_TRAILING_METADATA_KEY = "x-grpc-test-echo-trailing-bin"
@@ -66,7 +66,7 @@ def _maybe_echo_status_and_message(request, servicer_context):
servicer_context.set_details(request.response_status.message)
-class TestService(test_pb2.TestServiceServicer):
+class TestService(test_pb2_grpc.TestServiceServicer):
def EmptyCall(self, request, context):
_maybe_echo_metadata(context)
diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py
index 65f1604eb8..0ae2c97b42 100644
--- a/src/python/grpcio_tests/tests/interop/server.py
+++ b/src/python/grpcio_tests/tests/interop/server.py
@@ -34,7 +34,7 @@ import logging
import time
import grpc
-from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import test_pb2_grpc
from tests.interop import methods
from tests.interop import resources
@@ -53,7 +53,8 @@ def serve():
args = parser.parse_args()
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
- test_pb2.add_TestServiceServicer_to_server(methods.TestService(), server)
+ test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(),
+ server)
if args.use_tls:
private_key = resources.private_key()
certificate_chain = resources.certificate_chain()
diff --git a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
index db938e6545..6f9269dd40 100644
--- a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
+++ b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
@@ -42,6 +42,7 @@ import sys
import tempfile
import threading
import unittest
+import platform
import grpc
from grpc_tools import protoc
@@ -150,6 +151,8 @@ class CommonTestMixin(object):
self.assertEqual(expected_response, response)
+@unittest.skipIf(platform.python_implementation() == "PyPy",
+ "Skip test if run with PyPy")
class SameSeparateTest(unittest.TestCase, SeparateTestMixin):
def setUp(self):
@@ -191,6 +194,8 @@ class SameSeparateTest(unittest.TestCase, SeparateTestMixin):
shutil.rmtree(self.directory)
+@unittest.skipIf(platform.python_implementation() == "PyPy",
+ "Skip test if run with PyPy")
class SameCommonTest(unittest.TestCase, CommonTestMixin):
def setUp(self):
@@ -228,6 +233,8 @@ class SameCommonTest(unittest.TestCase, CommonTestMixin):
shutil.rmtree(self.directory)
+@unittest.skipIf(platform.python_implementation() == "PyPy",
+ "Skip test if run with PyPy")
class SplitCommonTest(unittest.TestCase, CommonTestMixin):
def setUp(self):
@@ -277,6 +284,8 @@ class SplitCommonTest(unittest.TestCase, CommonTestMixin):
shutil.rmtree(self.directory)
+@unittest.skipIf(platform.python_implementation() == "PyPy",
+ "Skip test if run with PyPy")
class SplitSeparateTest(unittest.TestCase, SeparateTestMixin):
def setUp(self):
diff --git a/src/python/grpcio_tests/tests/qps/qps_worker.py b/src/python/grpcio_tests/tests/qps/qps_worker.py
index 025dfb9d4a..7cd53e7bd9 100644
--- a/src/python/grpcio_tests/tests/qps/qps_worker.py
+++ b/src/python/grpcio_tests/tests/qps/qps_worker.py
@@ -33,7 +33,7 @@ import time
from concurrent import futures
import grpc
-from src.proto.grpc.testing import services_pb2
+from src.proto.grpc.testing import services_pb2_grpc
from tests.qps import worker_server
@@ -41,7 +41,7 @@ from tests.qps import worker_server
def run_worker_server(port):
server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
servicer = worker_server.WorkerServer()
- services_pb2.add_WorkerServiceServicer_to_server(servicer, server)
+ services_pb2_grpc.add_WorkerServiceServicer_to_server(servicer, server)
server.add_insecure_port('[::]:{}'.format(port))
server.start()
servicer.wait_for_quit()
diff --git a/src/python/grpcio_tests/tests/qps/worker_server.py b/src/python/grpcio_tests/tests/qps/worker_server.py
index ca1a777611..de9535f46e 100644
--- a/src/python/grpcio_tests/tests/qps/worker_server.py
+++ b/src/python/grpcio_tests/tests/qps/worker_server.py
@@ -35,7 +35,7 @@ import time
from concurrent import futures
import grpc
from src.proto.grpc.testing import control_pb2
-from src.proto.grpc.testing import services_pb2
+from src.proto.grpc.testing import services_pb2_grpc
from src.proto.grpc.testing import stats_pb2
from tests.qps import benchmark_client
@@ -45,7 +45,7 @@ from tests.qps import histogram
from tests.unit import resources
-class WorkerServer(services_pb2.WorkerServiceServicer):
+class WorkerServer(services_pb2_grpc.WorkerServiceServicer):
"""Python Worker Server implementation."""
def __init__(self):
@@ -87,8 +87,8 @@ class WorkerServer(services_pb2.WorkerServiceServicer):
futures.ThreadPoolExecutor(max_workers=server_threads))
if config.server_type == control_pb2.ASYNC_SERVER:
servicer = benchmark_server.BenchmarkServer()
- services_pb2.add_BenchmarkServiceServicer_to_server(servicer,
- server)
+ services_pb2_grpc.add_BenchmarkServiceServicer_to_server(servicer,
+ server)
elif config.server_type == control_pb2.ASYNC_GENERIC_SERVER:
resp_size = config.payload_config.bytebuf_params.resp_size
servicer = benchmark_server.GenericBenchmarkServer(resp_size)
diff --git a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
index d06ff064e2..4d73be6204 100644
--- a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
+++ b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
@@ -34,6 +34,7 @@ import grpc
from grpc.framework.foundation import logging_pool
from grpc_reflection.v1alpha import reflection
from grpc_reflection.v1alpha import reflection_pb2
+from grpc_reflection.v1alpha import reflection_pb2_grpc
from google.protobuf import descriptor_pool
from google.protobuf import descriptor_pb2
@@ -61,12 +62,12 @@ class ReflectionServicerTest(unittest.TestCase):
server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
self._server = grpc.server(server_pool)
port = self._server.add_insecure_port('[::]:0')
- reflection_pb2.add_ServerReflectionServicer_to_server(servicer,
- self._server)
+ reflection_pb2_grpc.add_ServerReflectionServicer_to_server(servicer,
+ self._server)
self._server.start()
channel = grpc.insecure_channel('localhost:%d' % port)
- self._stub = reflection_pb2.ServerReflectionStub(channel)
+ self._stub = reflection_pb2_grpc.ServerReflectionStub(channel)
def testFileByName(self):
requests = (reflection_pb2.ServerReflectionRequest(
diff --git a/src/python/grpcio_tests/tests/stress/client.py b/src/python/grpcio_tests/tests/stress/client.py
index b9dbe61d44..b7eb12bff8 100644
--- a/src/python/grpcio_tests/tests/stress/client.py
+++ b/src/python/grpcio_tests/tests/stress/client.py
@@ -34,7 +34,7 @@ import threading
import grpc
from six.moves import queue
-from src.proto.grpc.testing import metrics_pb2
+from src.proto.grpc.testing import metrics_pb2_grpc
from src.proto.grpc.testing import test_pb2
from tests.interop import methods
@@ -139,7 +139,7 @@ def run_test(args):
runners = []
server = grpc.server(futures.ThreadPoolExecutor(max_workers=25))
- metrics_pb2.add_MetricsServiceServicer_to_server(
+ metrics_pb2_grpc.add_MetricsServiceServicer_to_server(
metrics_server.MetricsServer(hist), server)
server.add_insecure_port('[::]:{}'.format(args.metrics_port))
server.start()
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 52465a4dd7..3ef6f0eb29 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -296,6 +296,7 @@ gpr_ref_type gpr_ref_import;
gpr_ref_non_zero_type gpr_ref_non_zero_import;
gpr_refn_type gpr_refn_import;
gpr_unref_type gpr_unref_import;
+gpr_ref_is_unique_type gpr_ref_is_unique_import;
gpr_stats_init_type gpr_stats_init_import;
gpr_stats_inc_type gpr_stats_inc_import;
gpr_stats_read_type gpr_stats_read_import;
@@ -589,6 +590,7 @@ void grpc_rb_load_imports(HMODULE library) {
gpr_ref_non_zero_import = (gpr_ref_non_zero_type) GetProcAddress(library, "gpr_ref_non_zero");
gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
+ gpr_ref_is_unique_import = (gpr_ref_is_unique_type) GetProcAddress(library, "gpr_ref_is_unique");
gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");
gpr_stats_inc_import = (gpr_stats_inc_type) GetProcAddress(library, "gpr_stats_inc");
gpr_stats_read_import = (gpr_stats_read_type) GetProcAddress(library, "gpr_stats_read");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 8ec7f6fd95..dccdbe7dc9 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -839,6 +839,9 @@ extern gpr_refn_type gpr_refn_import;
typedef int(*gpr_unref_type)(gpr_refcount *r);
extern gpr_unref_type gpr_unref_import;
#define gpr_unref gpr_unref_import
+typedef int(*gpr_ref_is_unique_type)(gpr_refcount *r);
+extern gpr_ref_is_unique_type gpr_ref_is_unique_import;
+#define gpr_ref_is_unique gpr_ref_is_unique_import
typedef void(*gpr_stats_init_type)(gpr_stats_counter *c, intptr_t n);
extern gpr_stats_init_type gpr_stats_init_import;
#define gpr_stats_init gpr_stats_init_import
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index ce0892decf..9901158e73 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '1.2.0.dev'
+ VERSION = '1.3.0.dev'
end
diff --git a/src/ruby/qps/proxy-worker.rb b/src/ruby/qps/proxy-worker.rb
new file mode 100755
index 0000000000..077920d1d3
--- /dev/null
+++ b/src/ruby/qps/proxy-worker.rb
@@ -0,0 +1,160 @@
+#!/usr/bin/env ruby
+
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Proxy of worker service implementation for running a PHP client
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'grpc'
+require 'optparse'
+require 'histogram'
+require 'etc'
+require 'facter'
+require 'qps-common'
+require 'src/proto/grpc/testing/services_services_pb'
+require 'src/proto/grpc/testing/proxy-service_services_pb'
+
+class ProxyBenchmarkClientServiceImpl < Grpc::Testing::ProxyClientService::Service
+ def initialize(port)
+ @mytarget = "localhost:" + port.to_s
+ end
+ def setup(config)
+ @config = config
+ @histres = config.histogram_params.resolution
+ @histmax = config.histogram_params.max_possible
+ @histogram = Histogram.new(@histres, @histmax)
+ @start_time = Time.now
+ # TODO(vjpai): Support multiple client channels by spawning off a PHP client per channel
+ command = "php " + File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/client.php " + @mytarget
+ puts "Starting command: " + command
+ @php_pid = spawn(command)
+ end
+ def stop
+ Process.kill("TERM", @php_pid)
+ Process.wait(@php_pid)
+ end
+ def get_config(_args, _call)
+ puts "Answering get_config"
+ @config
+ end
+ def report_time(call)
+ puts "Starting a time reporting stream"
+ call.each_remote_read do |lat|
+ @histogram.add((lat.latency)*1e9)
+ end
+ Grpc::Testing::Void.new
+ end
+ def mark(reset)
+ lat = Grpc::Testing::HistogramData.new(
+ bucket: @histogram.contents,
+ min_seen: @histogram.minimum,
+ max_seen: @histogram.maximum,
+ sum: @histogram.sum,
+ sum_of_squares: @histogram.sum_of_squares,
+ count: @histogram.count
+ )
+ elapsed = Time.now-@start_time
+ if reset
+ @start_time = Time.now
+ @histogram = Histogram.new(@histres, @histmax)
+ end
+ Grpc::Testing::ClientStats.new(latencies: lat, time_elapsed: elapsed)
+ end
+end
+
+class ProxyWorkerServiceImpl < Grpc::Testing::WorkerService::Service
+ def cpu_cores
+ Facter.value('processors')['count']
+ end
+ # Leave run_server unimplemented since this proxies for a client only.
+ # If the driver tries to use this as a server, it will get an unimplemented
+ # status return value.
+ def run_client(reqs)
+ q = EnumeratorQueue.new(self)
+ Thread.new {
+ reqs.each do |req|
+ case req.argtype.to_s
+ when 'setup'
+ @bmc.setup(req.setup)
+ q.push(Grpc::Testing::ClientStatus.new(stats: @bmc.mark(false)))
+ when 'mark'
+ q.push(Grpc::Testing::ClientStatus.new(stats:
+ @bmc.mark(req.mark.reset)))
+ end
+ end
+ @bmc.stop
+ q.push(self)
+ }
+ q.each_item
+ end
+ def core_count(_args, _call)
+ Grpc::Testing::CoreResponse.new(cores: cpu_cores)
+ end
+ def quit_worker(_args, _call)
+ Thread.new {
+ sleep 3
+ @server.stop
+ }
+ Grpc::Testing::Void.new
+ end
+ def initialize(s, bmc)
+ @server = s
+ @bmc = bmc
+ end
+end
+
+def proxymain
+ options = {
+ 'driver_port' => 0
+ }
+ OptionParser.new do |opts|
+ opts.banner = 'Usage: [--driver_port <port>]'
+ opts.on('--driver_port PORT', '<port>') do |v|
+ options['driver_port'] = v
+ end
+ end.parse!
+
+ # Configure any errors with client or server child threads to surface
+ Thread.abort_on_exception = true
+
+ s = GRPC::RpcServer.new
+ port = s.add_http2_port("0.0.0.0:" + options['driver_port'].to_s,
+ :this_port_is_insecure)
+ bmc = ProxyBenchmarkClientServiceImpl.new(port)
+ s.handle(bmc)
+ s.handle(ProxyWorkerServiceImpl.new(s, bmc))
+ s.run
+end
+
+proxymain
diff --git a/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb b/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb
new file mode 100644
index 0000000000..d238198cca
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb
@@ -0,0 +1,17 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/proxy-service.proto
+
+require 'google/protobuf'
+
+require 'src/proto/grpc/testing/control_pb'
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.ProxyStat" do
+ optional :latency, :double, 1
+ end
+end
+
+module Grpc
+ module Testing
+ ProxyStat = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ProxyStat").msgclass
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb b/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb
new file mode 100644
index 0000000000..37ddbf5b03
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb
@@ -0,0 +1,55 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: src/proto/grpc/testing/proxy-service.proto for package 'grpc.testing'
+# Original file comments:
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+require 'grpc'
+require 'src/proto/grpc/testing/proxy-service_pb'
+
+module Grpc
+ module Testing
+ module ProxyClientService
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.ProxyClientService'
+
+ rpc :GetConfig, Void, ClientConfig
+ rpc :ReportTime, stream(ProxyStat), Void
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 8f3d2ba81c..632c0100bd 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
module GRPC
module Tools
- VERSION = '1.2.0.dev'
+ VERSION = '1.3.0.dev'
end
end