aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/csharp_generator_helpers.h2
-rw-r--r--src/compiler/generator_helpers.h13
-rw-r--r--src/compiler/objective_c_generator.cc33
-rw-r--r--src/compiler/objective_c_plugin.cc28
-rw-r--r--src/core/census/census_filter.h2
-rw-r--r--src/core/channel/client_channel.c38
-rw-r--r--src/core/channel/client_channel.h7
-rw-r--r--src/core/channel/compress_filter.c57
-rw-r--r--src/core/channel/compress_filter.h2
-rw-r--r--src/core/channel/http_client_filter.h2
-rw-r--r--src/core/channel/http_server_filter.h2
-rw-r--r--src/core/channel/noop_filter.h2
-rw-r--r--src/core/client_config/resolvers/dns_resolver.c3
-rw-r--r--src/core/client_config/resolvers/zookeeper_resolver.c501
-rw-r--r--src/core/client_config/resolvers/zookeeper_resolver.h42
-rw-r--r--src/core/client_config/subchannel.h2
-rw-r--r--src/core/client_config/subchannel_factory_decorators/add_channel_arg.c10
-rw-r--r--src/core/client_config/subchannel_factory_decorators/add_channel_arg.h5
-rw-r--r--src/core/client_config/subchannel_factory_decorators/merge_channel_args.c4
-rw-r--r--src/core/client_config/subchannel_factory_decorators/merge_channel_args.h5
-rw-r--r--src/core/compression/algorithm.c17
-rw-r--r--src/core/debug/trace.c8
-rw-r--r--src/core/debug/trace.h2
-rw-r--r--src/core/httpcli/format_request.c6
-rw-r--r--src/core/httpcli/format_request.h2
-rw-r--r--src/core/httpcli/parser.h2
-rw-r--r--src/core/iomgr/alarm.c5
-rw-r--r--src/core/iomgr/alarm.h2
-rw-r--r--src/core/iomgr/alarm_heap.c10
-rw-r--r--src/core/iomgr/alarm_heap.h2
-rw-r--r--src/core/iomgr/alarm_internal.h2
-rw-r--r--src/core/iomgr/endpoint.c3
-rw-r--r--src/core/iomgr/endpoint.h5
-rw-r--r--src/core/iomgr/endpoint_pair.h2
-rw-r--r--src/core/iomgr/endpoint_pair_windows.c20
-rw-r--r--src/core/iomgr/iocp_windows.c35
-rw-r--r--src/core/iomgr/iocp_windows.h10
-rw-r--r--src/core/iomgr/iomgr.h2
-rw-r--r--src/core/iomgr/iomgr_internal.h2
-rw-r--r--src/core/iomgr/iomgr_posix.c2
-rw-r--r--src/core/iomgr/iomgr_posix.h2
-rw-r--r--src/core/iomgr/iomgr_windows.c2
-rw-r--r--src/core/iomgr/pollset_multipoller_with_epoll.c3
-rw-r--r--src/core/iomgr/pollset_multipoller_with_poll_posix.c5
-rw-r--r--src/core/iomgr/pollset_posix.c16
-rw-r--r--src/core/iomgr/pollset_posix.h3
-rw-r--r--src/core/iomgr/pollset_windows.c10
-rw-r--r--src/core/iomgr/resolve_address.h2
-rw-r--r--src/core/iomgr/resolve_address_posix.c5
-rw-r--r--src/core/iomgr/sockaddr.h2
-rw-r--r--src/core/iomgr/sockaddr_posix.h2
-rw-r--r--src/core/iomgr/sockaddr_utils.c6
-rw-r--r--src/core/iomgr/sockaddr_utils.h2
-rw-r--r--src/core/iomgr/sockaddr_win32.h2
-rw-r--r--src/core/iomgr/socket_utils_posix.h2
-rw-r--r--src/core/iomgr/socket_windows.c2
-rw-r--r--src/core/iomgr/socket_windows.h4
-rw-r--r--src/core/iomgr/tcp_client.h2
-rw-r--r--src/core/iomgr/tcp_client_posix.c3
-rw-r--r--src/core/iomgr/tcp_posix.c3
-rw-r--r--src/core/iomgr/tcp_posix.h2
-rw-r--r--src/core/iomgr/tcp_server_windows.c12
-rw-r--r--src/core/iomgr/tcp_windows.c59
-rw-r--r--src/core/iomgr/tcp_windows.h2
-rw-r--r--src/core/iomgr/time_averaged_stats.h2
-rw-r--r--src/core/iomgr/udp_server.c438
-rw-r--r--src/core/iomgr/udp_server.h85
-rw-r--r--src/core/iomgr/wakeup_fd_eventfd.c5
-rw-r--r--src/core/iomgr/wakeup_fd_nospecial.c9
-rw-r--r--src/core/iomgr/wakeup_fd_pipe.c2
-rw-r--r--src/core/iomgr/wakeup_fd_pipe.h2
-rw-r--r--src/core/iomgr/wakeup_fd_posix.c6
-rw-r--r--src/core/iomgr/wakeup_fd_posix.h2
-rw-r--r--src/core/json/json.h2
-rw-r--r--src/core/json/json_common.h2
-rw-r--r--src/core/json/json_reader.c36
-rw-r--r--src/core/json/json_reader.h2
-rw-r--r--src/core/json/json_string.c50
-rw-r--r--src/core/json/json_writer.c33
-rw-r--r--src/core/json/json_writer.h14
-rw-r--r--src/core/profiling/timers.h2
-rw-r--r--src/core/security/auth_filters.h2
-rw-r--r--src/core/security/base64.h2
-rw-r--r--src/core/security/client_auth_filter.c8
-rw-r--r--src/core/security/credentials.c20
-rw-r--r--src/core/security/credentials.h5
-rw-r--r--src/core/security/credentials_metadata.c4
-rw-r--r--src/core/security/google_default_credentials.c4
-rw-r--r--src/core/security/json_token.h2
-rw-r--r--src/core/security/jwt_verifier.h1
-rw-r--r--src/core/security/secure_endpoint.c2
-rw-r--r--src/core/security/secure_endpoint.h2
-rw-r--r--src/core/security/secure_transport_setup.h2
-rw-r--r--src/core/security/security_context.c4
-rw-r--r--src/core/security/security_context.h3
-rw-r--r--src/core/security/server_auth_filter.c3
-rw-r--r--src/core/statistics/census_interface.h2
-rw-r--r--src/core/statistics/census_log.h2
-rw-r--r--src/core/statistics/census_rpc_stats.c4
-rw-r--r--src/core/statistics/census_rpc_stats.h2
-rw-r--r--src/core/statistics/census_tracing.c7
-rw-r--r--src/core/statistics/census_tracing.h2
-rw-r--r--src/core/statistics/hash_table.h2
-rw-r--r--src/core/support/cancellable.c157
-rw-r--r--src/core/support/cpu_iphone.c8
-rw-r--r--src/core/support/cpu_linux.c2
-rw-r--r--src/core/support/env.h2
-rw-r--r--src/core/support/file.h2
-rw-r--r--src/core/support/histogram.c11
-rw-r--r--src/core/support/log_linux.c4
-rw-r--r--src/core/support/murmur_hash.h2
-rw-r--r--src/core/support/slice.c3
-rw-r--r--src/core/support/slice_buffer.c3
-rw-r--r--src/core/support/stack_lockfree.c20
-rw-r--r--src/core/support/string.c19
-rw-r--r--src/core/support/string.h4
-rw-r--r--src/core/support/string_win32.c8
-rw-r--r--src/core/support/string_win32.h4
-rw-r--r--src/core/support/sync.c15
-rw-r--r--src/core/support/sync_posix.c3
-rw-r--r--src/core/support/sync_win32.c3
-rw-r--r--src/core/support/thd.c4
-rw-r--r--src/core/support/thd_internal.h2
-rw-r--r--src/core/support/thd_posix.c14
-rw-r--r--src/core/support/thd_win32.c4
-rw-r--r--src/core/support/time.c3
-rw-r--r--src/core/support/tls_pthread.c2
-rw-r--r--src/core/surface/byte_buffer_queue.h2
-rw-r--r--src/core/surface/call.c104
-rw-r--r--src/core/surface/call.h19
-rw-r--r--src/core/surface/call_log_batch.c15
-rw-r--r--src/core/surface/channel.c45
-rw-r--r--src/core/surface/channel.h2
-rw-r--r--src/core/surface/channel_connectivity.c16
-rw-r--r--src/core/surface/channel_create.c4
-rw-r--r--src/core/surface/completion_queue.c14
-rw-r--r--src/core/surface/event_string.h2
-rw-r--r--src/core/surface/init.c32
-rw-r--r--src/core/surface/init.h2
-rw-r--r--src/core/surface/init_unsecure.c3
-rw-r--r--src/core/surface/lame_client.c25
-rw-r--r--src/core/surface/secure_channel_create.c8
-rw-r--r--src/core/surface/server.c19
-rw-r--r--src/core/surface/server_create.c3
-rw-r--r--src/core/surface/surface_trace.h4
-rw-r--r--src/core/transport/chttp2/frame_data.c4
-rw-r--r--src/core/transport/chttp2/parsing.c7
-rw-r--r--src/core/transport/chttp2/stream_lists.c2
-rw-r--r--src/core/transport/chttp2/stream_map.c3
-rw-r--r--src/core/transport/chttp2/writing.c29
-rw-r--r--src/core/transport/chttp2_transport.c22
-rw-r--r--src/core/transport/metadata.c13
-rw-r--r--src/core/transport/metadata.h5
-rw-r--r--src/core/transport/stream_op.c7
-rw-r--r--src/core/transport/stream_op.h1
-rw-r--r--src/core/tsi/fake_transport_security.c11
-rw-r--r--src/core/tsi/fake_transport_security.h2
-rw-r--r--src/core/tsi/ssl_transport_security.c31
-rw-r--r--src/core/tsi/ssl_transport_security.h2
-rw-r--r--src/core/tsi/transport_security.h2
-rw-r--r--src/core/tsi/transport_security_interface.h2
-rw-r--r--src/cpp/client/channel.cc13
-rw-r--r--src/cpp/client/channel.h5
-rw-r--r--src/cpp/client/client_context.cc8
-rw-r--r--src/cpp/client/create_channel.cc4
-rw-r--r--src/cpp/client/insecure_credentials.cc2
-rw-r--r--src/cpp/client/secure_credentials.h1
-rw-r--r--src/cpp/common/auth_property_iterator.cc6
-rw-r--r--src/cpp/common/completion_queue.cc14
-rw-r--r--src/cpp/proto/proto_utils.cc13
-rw-r--r--src/cpp/server/create_default_thread_pool.cc6
-rw-r--r--src/cpp/server/dynamic_thread_pool.cc24
-rw-r--r--src/cpp/server/secure_server_credentials.cc4
-rw-r--r--src/cpp/server/server.cc105
-rw-r--r--src/cpp/server/server_builder.cc31
-rw-r--r--src/cpp/server/server_context.cc8
-rw-r--r--src/csharp/Grpc.Auth/AuthInterceptors.cs84
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj42
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.nuspec2
-rw-r--r--src/csharp/Grpc.Auth/OAuth2Interceptors.cs115
-rw-r--r--src/csharp/Grpc.Core/AsyncClientStreamingCall.cs18
-rw-r--r--src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs2
-rw-r--r--src/csharp/Grpc.Core/AsyncServerStreamingCall.cs2
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs2
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs18
-rw-r--r--src/csharp/Grpc.Core/Method.cs29
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs12
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c73
-rw-r--r--src/node/README.md32
-rw-r--r--src/node/examples/perf_test.js2
-rw-r--r--src/node/examples/qps_test.js2
-rw-r--r--src/node/examples/route_guide_server.js2
-rw-r--r--src/node/examples/stock_server.js2
-rw-r--r--src/node/ext/call.cc44
-rw-r--r--src/node/ext/call.h13
-rw-r--r--src/node/ext/channel.cc64
-rw-r--r--src/node/ext/channel.h2
-rw-r--r--src/node/ext/completion_queue_async_worker.cc6
-rw-r--r--src/node/ext/node_grpc.cc50
-rw-r--r--src/node/ext/server.cc14
-rw-r--r--src/node/index.js10
-rw-r--r--src/node/interop/interop_client.js4
-rw-r--r--src/node/interop/interop_server.js2
-rw-r--r--src/node/src/client.js54
-rw-r--r--src/node/src/server.js27
-rw-r--r--src/node/test/channel_test.js87
-rw-r--r--src/node/test/constant_test.js37
-rw-r--r--src/node/test/server_test.js4
-rw-r--r--src/node/test/surface_test.js241
-rw-r--r--src/objective-c/GRPCClient/private/GRPCCompletionQueue.m5
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m2
-rw-r--r--src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m2
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.m4
-rw-r--r--src/php/README.md46
-rw-r--r--src/php/ext/grpc/call.c34
-rw-r--r--src/php/ext/grpc/channel.c84
-rwxr-xr-xsrc/php/ext/grpc/channel.h1
-rw-r--r--src/php/ext/grpc/completion_queue.c7
-rw-r--r--src/php/ext/grpc/php_grpc.c12
-rw-r--r--src/php/ext/grpc/server.c11
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php45
-rwxr-xr-xsrc/php/tests/interop/interop_client.php2
-rwxr-xr-xsrc/php/tests/unit_tests/EndToEndTest.php46
-rwxr-xr-xsrc/php/tests/unit_tests/SecureEndToEndTest.php14
-rw-r--r--src/python/README.md37
-rw-r--r--src/python/grpcio/README.rst3
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/call.c6
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/channel.c4
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c4
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/server.c4
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/utility.c1
-rw-r--r--src/python/grpcio/grpc/_links/service.py43
-rw-r--r--src/python/grpcio/grpc/early_adopter/implementations.py30
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/base/__init__.py (renamed from src/ruby/bin/interop/test/cpp/interop/test.rb)13
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/base/base.py273
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/base/utilities.py79
-rw-r--r--src/python/grpcio_test/grpc_test/framework/common/test_constants.py10
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py (renamed from src/ruby/bin/interop/test/cpp/interop/empty.rb)14
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py568
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py168
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py (renamed from src/ruby/bin/interop/test/cpp/interop/test_services.rb)57
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py260
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py186
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py9
-rwxr-xr-xsrc/ruby/.rspec1
-rw-r--r--src/ruby/.rubocop.yml3
-rw-r--r--src/ruby/README.md38
-rwxr-xr-xsrc/ruby/Rakefile6
-rwxr-xr-xsrc/ruby/bin/grpc_ruby_interop_client33
-rwxr-xr-xsrc/ruby/bin/grpc_ruby_interop_server33
-rw-r--r--src/ruby/bin/interop/README.md8
-rwxr-xr-xsrc/ruby/bin/interop/interop_client.rb344
-rwxr-xr-xsrc/ruby/bin/interop/interop_server.rb162
-rw-r--r--src/ruby/ext/grpc/rb_call.c13
-rw-r--r--src/ruby/ext/grpc/rb_channel.c4
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.c6
-rw-r--r--src/ruby/ext/grpc/rb_server.c4
-rwxr-xr-xsrc/ruby/grpc.gemspec10
-rw-r--r--src/ruby/lib/grpc/generic/active_call.rb9
-rw-r--r--src/ruby/lib/grpc/generic/bidi_call.rb29
-rw-r--r--src/ruby/lib/grpc/generic/client_stub.rb53
-rw-r--r--src/ruby/lib/grpc/generic/service.rb18
-rw-r--r--src/ruby/lib/grpc/logconfig.rb36
-rw-r--r--src/ruby/pb/README.md42
-rw-r--r--src/ruby/pb/grpc/health/checker.rb75
-rw-r--r--src/ruby/pb/grpc/health/v1alpha/health.proto50
-rw-r--r--src/ruby/pb/grpc/health/v1alpha/health.rb29
-rw-r--r--src/ruby/pb/grpc/health/v1alpha/health_services.rb28
-rwxr-xr-xsrc/ruby/pb/test/client.rb453
-rw-r--r--src/ruby/pb/test/proto/empty.rb15
-rw-r--r--src/ruby/pb/test/proto/messages.rb (renamed from src/ruby/bin/interop/test/cpp/interop/messages.rb)51
-rw-r--r--src/ruby/pb/test/proto/test.rb14
-rw-r--r--src/ruby/pb/test/proto/test_services.rb64
-rwxr-xr-xsrc/ruby/pb/test/server.rb196
-rw-r--r--src/ruby/spec/generic/active_call_spec.rb29
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb20
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb9
-rw-r--r--src/ruby/spec/pb/health/checker_spec.rb233
-rw-r--r--src/ruby/spec/spec_helper.rb14
279 files changed, 6296 insertions, 1852 deletions
diff --git a/src/compiler/csharp_generator_helpers.h b/src/compiler/csharp_generator_helpers.h
index 1370627633..5639ea058b 100644
--- a/src/compiler/csharp_generator_helpers.h
+++ b/src/compiler/csharp_generator_helpers.h
@@ -41,7 +41,7 @@ namespace grpc_csharp_generator {
inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
grpc::string *file_name_or_error) {
- *file_name_or_error = grpc_generator::FileNameInUpperCamel(file) + "Grpc.cs";
+ *file_name_or_error = grpc_generator::FileNameInUpperCamel(file, false) + "Grpc.cs";
return true;
}
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 68b807b057..e1bb66a875 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -125,16 +125,23 @@ inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) {
return result;
}
-inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file,
+ bool include_package_path) {
std::vector<grpc::string> tokens = tokenize(StripProto(file->name()), "/");
grpc::string result = "";
- for (unsigned int i = 0; i < tokens.size() - 1; i++) {
- result += tokens[i] + "/";
+ if (include_package_path) {
+ for (unsigned int i = 0; i < tokens.size() - 1; i++) {
+ result += tokens[i] + "/";
+ }
}
result += LowerUnderscoreToUpperCamel(tokens.back());
return result;
}
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+ return FileNameInUpperCamel(file, true);
+}
+
enum MethodType {
METHODTYPE_NO_STREAMING,
METHODTYPE_CLIENT_STREAMING,
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 483c6573a8..a3157db0fb 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -44,7 +44,6 @@ using ::google::protobuf::compiler::objectivec::ClassName;
using ::grpc::protobuf::io::Printer;
using ::grpc::protobuf::MethodDescriptor;
using ::grpc::protobuf::ServiceDescriptor;
-using ::grpc::string;
using ::std::map;
namespace grpc_objective_c_generator {
@@ -52,7 +51,7 @@ namespace {
void PrintProtoRpcDeclarationAsPragma(Printer *printer,
const MethodDescriptor *method,
- map<string, string> vars) {
+ map< ::grpc::string, ::grpc::string> vars) {
vars["client_stream"] = method->client_streaming() ? "stream " : "";
vars["server_stream"] = method->server_streaming() ? "stream " : "";
@@ -62,7 +61,7 @@ void PrintProtoRpcDeclarationAsPragma(Printer *printer,
}
void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
- const map<string, string> &vars) {
+ const map< ::grpc::string, ::grpc::string> &vars) {
// TODO(jcanizales): Print method comments.
printer->Print(vars, "- ($return_type$)$method_name$With");
@@ -85,7 +84,7 @@ void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
}
void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
- map<string, string> vars) {
+ map< ::grpc::string, ::grpc::string> vars) {
vars["method_name"] =
grpc_generator::LowercaseFirstLetter(vars["method_name"]);
vars["return_type"] = "void";
@@ -93,14 +92,14 @@ void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
}
void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
- map<string, string> vars) {
+ map< ::grpc::string, ::grpc::string> vars) {
vars["method_name"] = "RPCTo" + vars["method_name"];
vars["return_type"] = "ProtoRPC *";
PrintMethodSignature(printer, method, vars);
}
-inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
- map<string, string> res;
+inline map< ::grpc::string, ::grpc::string> GetMethodVars(const MethodDescriptor *method) {
+ map< ::grpc::string, ::grpc::string> res;
res["method_name"] = method->name();
res["request_type"] = method->input_type()->name();
res["response_type"] = method->output_type()->name();
@@ -110,7 +109,7 @@ inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
}
void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
- map<string, string> vars = GetMethodVars(method);
+ map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
PrintProtoRpcDeclarationAsPragma(printer, method, vars);
@@ -121,7 +120,7 @@ void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
}
void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
- map<string, string> vars) {
+ map< ::grpc::string, ::grpc::string> vars) {
printer->Print("{\n");
printer->Print(vars, " [[self RPCTo$method_name$With");
if (method->client_streaming()) {
@@ -139,7 +138,7 @@ void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
void PrintAdvancedImplementation(Printer *printer,
const MethodDescriptor *method,
- map<string, string> vars) {
+ map< ::grpc::string, ::grpc::string> vars) {
printer->Print("{\n");
printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n");
@@ -164,7 +163,7 @@ void PrintAdvancedImplementation(Printer *printer,
void PrintMethodImplementations(Printer *printer,
const MethodDescriptor *method) {
- map<string, string> vars = GetMethodVars(method);
+ map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
PrintProtoRpcDeclarationAsPragma(printer, method, vars);
@@ -179,14 +178,14 @@ void PrintMethodImplementations(Printer *printer,
} // namespace
-string GetHeader(const ServiceDescriptor *service) {
- string output;
+::grpc::string GetHeader(const ServiceDescriptor *service) {
+ ::grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
- map<string, string> vars = {{"service_class", ServiceClassName(service)}};
+ map< ::grpc::string, ::grpc::string> vars = {{"service_class", ServiceClassName(service)}};
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
@@ -209,14 +208,14 @@ string GetHeader(const ServiceDescriptor *service) {
return output;
}
-string GetSource(const ServiceDescriptor *service) {
- string output;
+::grpc::string GetSource(const ServiceDescriptor *service) {
+ ::grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
- map<string, string> vars = {{"service_name", service->name()},
+ map< ::grpc::string,::grpc::string> vars = {{"service_name", service->name()},
{"service_class", ServiceClassName(service)},
{"package", service->file()->package()}};
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 10f06ad4df..17440358bb 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -39,44 +39,43 @@
#include "src/compiler/objective_c_generator.h"
#include "src/compiler/objective_c_generator_helpers.h"
-using ::grpc::string;
-
class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
ObjectiveCGrpcGenerator() {}
virtual ~ObjectiveCGrpcGenerator() {}
virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
- const string &parameter,
+ const ::grpc::string &parameter,
grpc::protobuf::compiler::GeneratorContext *context,
- string *error) const {
+ ::grpc::string *error) const {
if (file->service_count() == 0) {
// No services. Do nothing.
return true;
}
- string file_name = grpc_generator::FileNameInUpperCamel(file);
- string prefix = file->options().objc_class_prefix();
+ ::grpc::string file_name = grpc_generator::FileNameInUpperCamel(file);
+ ::grpc::string prefix = file->options().objc_class_prefix();
{
// Generate .pbrpc.h
- string imports = string("#import \"") + file_name + ".pbobjc.h\"\n\n"
+ ::grpc::string imports = ::grpc::string("#import \"") + file_name +
+ ".pbobjc.h\"\n\n"
"#import <ProtoRPC/ProtoService.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n"
"#import <RxLibrary/GRXWriter.h>\n";
// TODO(jcanizales): Instead forward-declare the input and output types
// and import the files in the .pbrpc.m
- string proto_imports;
+ ::grpc::string proto_imports;
for (int i = 0; i < file->dependency_count(); i++) {
- string header = grpc_objective_c_generator::MessageHeaderName(
+ ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(
file->dependency(i));
- proto_imports += string("#import \"") + header + "\"\n";
+ proto_imports += ::grpc::string("#import \"") + header + "\"\n";
}
- string declarations;
+ ::grpc::string declarations;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor *service = file->service(i);
declarations += grpc_objective_c_generator::GetHeader(service);
@@ -89,11 +88,12 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
{
// Generate .pbrpc.m
- string imports = string("#import \"") + file_name + ".pbrpc.h\"\n\n"
+ ::grpc::string imports = ::grpc::string("#import \"") + file_name +
+ ".pbrpc.h\"\n\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriter+Immediate.h>\n";
- string definitions;
+ ::grpc::string definitions;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor *service = file->service(i);
definitions += grpc_objective_c_generator::GetSource(service);
@@ -108,7 +108,7 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
private:
// Write the given code into the given file.
void Write(grpc::protobuf::compiler::GeneratorContext *context,
- const string &filename, const string &code) const {
+ const ::grpc::string &filename, const ::grpc::string &code) const {
std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
context->Open(filename));
grpc::protobuf::io::CodedOutputStream coded_out(output.get());
diff --git a/src/core/census/census_filter.h b/src/core/census/census_filter.h
index 4f9759f0db..1453c05d28 100644
--- a/src/core/census/census_filter.h
+++ b/src/core/census/census_filter.h
@@ -41,4 +41,4 @@
extern const grpc_channel_filter grpc_client_census_filter;
extern const grpc_channel_filter grpc_server_census_filter;
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 6c2e6b38a8..2e25033813 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -84,8 +84,10 @@ typedef struct {
grpc_pollset_set pollset_set;
} channel_data;
-/** We create one watcher for each new lb_policy that is returned from a resolver,
- to watch for state changes from the lb_policy. When a state change is seen, we
+/** We create one watcher for each new lb_policy that is returned from a
+ resolver,
+ to watch for state changes from the lb_policy. When a state change is seen,
+ we
update the channel, and create a new watcher */
typedef struct {
channel_data *chand;
@@ -380,7 +382,8 @@ static void perform_transport_stream_op(grpc_call_element *elem,
if (lb_policy) {
grpc_transport_stream_op *op = &calld->waiting_op;
grpc_pollset *bind_pollset = op->bind_pollset;
- grpc_metadata_batch *initial_metadata = &op->send_ops->ops[0].data.metadata;
+ grpc_metadata_batch *initial_metadata =
+ &op->send_ops->ops[0].data.metadata;
GRPC_LB_POLICY_REF(lb_policy, "pick");
gpr_mu_unlock(&chand->mu_config);
calld->state = CALL_WAITING_FOR_PICK;
@@ -388,13 +391,14 @@ static void perform_transport_stream_op(grpc_call_element *elem,
GPR_ASSERT(op->bind_pollset);
GPR_ASSERT(op->send_ops);
GPR_ASSERT(op->send_ops->nops >= 1);
- GPR_ASSERT(
- op->send_ops->ops[0].type == GRPC_OP_METADATA);
+ GPR_ASSERT(op->send_ops->ops[0].type == GRPC_OP_METADATA);
gpr_mu_unlock(&calld->mu_state);
- grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld);
+ grpc_iomgr_closure_init(&calld->async_setup_task, picked_target,
+ calld);
grpc_lb_policy_pick(lb_policy, bind_pollset, initial_metadata,
- &calld->picked_channel, &calld->async_setup_task);
+ &calld->picked_channel,
+ &calld->async_setup_task);
GRPC_LB_POLICY_UNREF(lb_policy, "pick");
} else if (chand->resolver != NULL) {
@@ -430,7 +434,8 @@ static void cc_start_transport_stream_op(grpc_call_element *elem,
perform_transport_stream_op(elem, op, 0);
}
-static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state);
+static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy,
+ grpc_connectivity_state current_state);
static void on_lb_policy_state_changed(void *arg, int iomgr_success) {
lb_policy_connectivity_watcher *w = arg;
@@ -450,7 +455,8 @@ static void on_lb_policy_state_changed(void *arg, int iomgr_success) {
gpr_free(w);
}
-static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) {
+static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy,
+ grpc_connectivity_state current_state) {
lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy");
@@ -499,13 +505,13 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
if (iomgr_success && chand->resolver) {
grpc_resolver *resolver = chand->resolver;
GRPC_RESOLVER_REF(resolver, "channel-next");
+ grpc_connectivity_state_set(&chand->state_tracker, state,
+ "new_lb+resolver");
gpr_mu_unlock(&chand->mu_config);
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(resolver, "channel-next");
- grpc_connectivity_state_set(&chand->state_tracker, state,
- "new_lb+resolver");
if (lb_policy != NULL) {
watch_lb_policy(chand, lb_policy, state);
}
@@ -663,7 +669,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed,
chand);
- grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel");
+ grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
+ "client_channel");
}
/* Destructor for channel_data */
@@ -747,19 +754,20 @@ void grpc_client_channel_watch_connectivity_state(
gpr_mu_unlock(&chand->mu_config);
}
-grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem) {
+grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
+ grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
return &chand->pollset_set;
}
void grpc_client_channel_add_interested_party(grpc_channel_element *elem,
- grpc_pollset *pollset) {
+ grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_add_pollset(&chand->pollset_set, pollset);
}
void grpc_client_channel_del_interested_party(grpc_channel_element *elem,
- grpc_pollset *pollset) {
+ grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_del_pollset(&chand->pollset_set, pollset);
}
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
index cd81294eb3..13681e3956 100644
--- a/src/core/channel/client_channel.h
+++ b/src/core/channel/client_channel.h
@@ -59,11 +59,12 @@ void grpc_client_channel_watch_connectivity_state(
grpc_channel_element *elem, grpc_connectivity_state *state,
grpc_iomgr_closure *on_complete);
-grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem);
+grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
+ grpc_channel_element *elem);
void grpc_client_channel_add_interested_party(grpc_channel_element *channel,
- grpc_pollset *pollset);
+ grpc_pollset *pollset);
void grpc_client_channel_del_interested_party(grpc_channel_element *channel,
- grpc_pollset *pollset);
+ grpc_pollset *pollset);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 8963c13b0f..762a4edc73 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -35,22 +35,25 @@
#include <string.h>
#include <grpc/compression.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
#include "src/core/compression/message_compress.h"
+#include "src/core/support/string.h"
typedef struct call_data {
gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
grpc_linked_mdelem compression_algorithm_storage;
+ grpc_linked_mdelem accept_encoding_storage;
int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */
int written_initial_metadata; /**< Already processed initial md? */
/** Compression algorithm we'll try to use. It may be given by incoming
* metadata, or by the channel's default compression settings. */
grpc_compression_algorithm compression_algorithm;
- /** If true, contents of \a compression_algorithm are authoritative */
+ /** If true, contents of \a compression_algorithm are authoritative */
int has_compression_algorithm;
} call_data;
@@ -59,8 +62,12 @@ typedef struct channel_data {
grpc_mdstr *mdstr_request_compression_algorithm_key;
/** Metadata key for the outgoing (used) compression algorithm */
grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
+ /** Metadata key for the accepted encodings */
+ grpc_mdstr *mdstr_compression_capabilities_key;
/** Precomputed metadata elements for all available compression algorithms */
grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
+ /** Precomputed metadata elements for the accepted encodings */
+ grpc_mdelem *mdelem_accept_encoding;
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
} channel_data;
@@ -71,7 +78,7 @@ typedef struct channel_data {
*
* Returns 1 if the data was actually compress and 0 otherwise. */
static int compress_send_sb(grpc_compression_algorithm algorithm,
- gpr_slice_buffer *slices) {
+ gpr_slice_buffer *slices) {
int did_compress;
gpr_slice_buffer tmp;
gpr_slice_buffer_init(&tmp);
@@ -86,14 +93,14 @@ static int compress_send_sb(grpc_compression_algorithm algorithm,
/** For each \a md element from the incoming metadata, filter out the entry for
* "grpc-encoding", using its value to populate the call data's
* compression_algorithm field. */
-static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
if (md->key == channeld->mdstr_request_compression_algorithm_key) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
- if (!grpc_compression_algorithm_parse(md_c_str,
+ if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
&calld->compression_algorithm)) {
gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.",
md_c_str);
@@ -108,10 +115,10 @@ static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) {
static int skip_compression(channel_data *channeld, call_data *calld) {
if (calld->has_compression_algorithm) {
- if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
- return 1;
- }
- return 0; /* we have an actual call-specific algorithm */
+ if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
+ return 1;
+ }
+ return 0; /* we have an actual call-specific algorithm */
}
/* no per-call compression override */
return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE;
@@ -184,7 +191,7 @@ static void process_send_ops(grpc_call_element *elem,
* given by GRPC_OP_BEGIN_MESSAGE) */
calld->remaining_slice_bytes = sop->data.begin_message.length;
if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) {
- calld->has_compression_algorithm = 1; /* GPR_TRUE */
+ calld->has_compression_algorithm = 1; /* GPR_TRUE */
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
break;
@@ -202,10 +209,17 @@ static void process_send_ops(grpc_call_element *elem,
channeld->default_compression_algorithm;
calld->has_compression_algorithm = 1; /* GPR_TRUE */
}
+ /* hint compression algorithm */
grpc_metadata_batch_add_tail(
&(sop->data.metadata), &calld->compression_algorithm_storage,
GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms
[calld->compression_algorithm]));
+
+ /* convey supported compression algorithms */
+ grpc_metadata_batch_add_tail(
+ &(sop->data.metadata), &calld->accept_encoding_storage,
+ GRPC_MDELEM_REF(channeld->mdelem_accept_encoding));
+
calld->written_initial_metadata = 1; /* GPR_TRUE */
}
break;
@@ -279,6 +293,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
int is_first, int is_last) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
+ const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1];
+ char *accept_encoding_str;
+ size_t accept_encoding_str_len;
channeld->default_compression_algorithm =
grpc_channel_args_get_compression_algorithm(args);
@@ -289,6 +306,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
channeld->mdstr_outgoing_compression_algorithm_key =
grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
+ channeld->mdstr_compression_capabilities_key =
+ grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0);
+
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
char *algorithm_name;
GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
@@ -297,8 +317,22 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
mdctx,
GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
grpc_mdstr_from_string(mdctx, algorithm_name, 0));
+ if (algo_idx > 0) {
+ supported_algorithms_names[algo_idx - 1] = algorithm_name;
+ }
}
+ /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated
+ * arrays, as to avoid the heap allocs */
+ accept_encoding_str = gpr_strjoin_sep(
+ supported_algorithms_names, GPR_ARRAY_SIZE(supported_algorithms_names),
+ ", ", &accept_encoding_str_len);
+
+ channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings(
+ mdctx, GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key),
+ grpc_mdstr_from_string(mdctx, accept_encoding_str, 0));
+ gpr_free(accept_encoding_str);
+
GPR_ASSERT(!is_last);
}
@@ -309,10 +343,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key);
GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key);
- for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT;
- ++algo_idx) {
+ GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key);
+ for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]);
}
+ GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding);
}
const grpc_channel_filter grpc_compress_filter = {
diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h
index 0694e2c1dd..0917e81ca4 100644
--- a/src/core/channel/compress_filter.h
+++ b/src/core/channel/compress_filter.h
@@ -62,4 +62,4 @@
extern const grpc_channel_filter grpc_compress_filter;
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */
diff --git a/src/core/channel/http_client_filter.h b/src/core/channel/http_client_filter.h
index 04eb839e00..21c66b9b8e 100644
--- a/src/core/channel/http_client_filter.h
+++ b/src/core/channel/http_client_filter.h
@@ -41,4 +41,4 @@ extern const grpc_channel_filter grpc_http_client_filter;
#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/channel/http_server_filter.h b/src/core/channel/http_server_filter.h
index 42f76ed17f..f219d4e66f 100644
--- a/src/core/channel/http_server_filter.h
+++ b/src/core/channel/http_server_filter.h
@@ -39,4 +39,4 @@
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_server_filter;
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */
diff --git a/src/core/channel/noop_filter.h b/src/core/channel/noop_filter.h
index 96463e5322..ded9b33117 100644
--- a/src/core/channel/noop_filter.h
+++ b/src/core/channel/noop_filter.h
@@ -41,4 +41,4 @@
customize for their own filters */
extern const grpc_channel_filter grpc_no_op_filter;
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 827b1a2be5..7b35b7902f 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -219,7 +219,8 @@ static grpc_resolver *dns_create(
default_host_arg.type = GRPC_ARG_STRING;
default_host_arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
default_host_arg.value.string = host;
- subchannel_factory = grpc_subchannel_factory_add_channel_arg(subchannel_factory, &default_host_arg);
+ subchannel_factory = grpc_subchannel_factory_add_channel_arg(
+ subchannel_factory, &default_host_arg);
gpr_free(host);
gpr_free(port);
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c
new file mode 100644
index 0000000000..acb2ba136e
--- /dev/null
+++ b/src/core/client_config/resolvers/zookeeper_resolver.c
@@ -0,0 +1,501 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/client_config/resolvers/zookeeper_resolver.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include <grpc/grpc_zookeeper.h>
+#include <zookeeper/zookeeper.h>
+
+#include "src/core/client_config/lb_policies/pick_first.h"
+#include "src/core/client_config/resolver_registry.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/support/string.h"
+#include "src/core/json/json.h"
+
+/** Zookeeper session expiration time in milliseconds */
+#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
+
+typedef struct {
+ /** base class: must be first */
+ grpc_resolver base;
+ /** refcount */
+ gpr_refcount refs;
+ /** name to resolve */
+ char *name;
+ /** subchannel factory */
+ grpc_subchannel_factory *subchannel_factory;
+ /** load balancing policy factory */
+ grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+ size_t num_subchannels);
+
+ /** mutex guarding the rest of the state */
+ gpr_mu mu;
+ /** are we currently resolving? */
+ int resolving;
+ /** which version of resolved_config have we published? */
+ int published_version;
+ /** which version of resolved_config is current? */
+ int resolved_version;
+ /** pending next completion, or NULL */
+ grpc_iomgr_closure *next_completion;
+ /** target config address for next completion */
+ grpc_client_config **target_config;
+ /** current (fully resolved) config */
+ grpc_client_config *resolved_config;
+
+ /** zookeeper handle */
+ zhandle_t *zookeeper_handle;
+ /** zookeeper resolved addresses */
+ grpc_resolved_addresses *resolved_addrs;
+ /** total number of addresses to be resolved */
+ int resolved_total;
+ /** number of addresses resolved */
+ int resolved_num;
+} zookeeper_resolver;
+
+static void zookeeper_destroy(grpc_resolver *r);
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
+static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r);
+
+static void zookeeper_shutdown(grpc_resolver *r);
+static void zookeeper_channel_saw_error(grpc_resolver *r,
+ struct sockaddr *failing_address,
+ int failing_address_len);
+static void zookeeper_next(grpc_resolver *r, grpc_client_config **target_config,
+ grpc_iomgr_closure *on_complete);
+
+static const grpc_resolver_vtable zookeeper_resolver_vtable = {
+ zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
+ zookeeper_next};
+
+static void zookeeper_shutdown(grpc_resolver *resolver) {
+ zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+ gpr_mu_lock(&r->mu);
+ if (r->next_completion != NULL) {
+ *r->target_config = NULL;
+ grpc_iomgr_add_callback(r->next_completion);
+ r->next_completion = NULL;
+ }
+ zookeeper_close(r->zookeeper_handle);
+ gpr_mu_unlock(&r->mu);
+}
+
+static void zookeeper_channel_saw_error(grpc_resolver *resolver,
+ struct sockaddr *sa, int len) {
+ zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+ gpr_mu_lock(&r->mu);
+ if (r->resolving == 0) {
+ zookeeper_start_resolving_locked(r);
+ }
+ gpr_mu_unlock(&r->mu);
+}
+
+static void zookeeper_next(grpc_resolver *resolver,
+ grpc_client_config **target_config,
+ grpc_iomgr_closure *on_complete) {
+ zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+ gpr_mu_lock(&r->mu);
+ GPR_ASSERT(r->next_completion == NULL);
+ r->next_completion = on_complete;
+ r->target_config = target_config;
+ if (r->resolved_version == 0 && r->resolving == 0) {
+ zookeeper_start_resolving_locked(r);
+ } else {
+ zookeeper_maybe_finish_next_locked(r);
+ }
+ gpr_mu_unlock(&r->mu);
+}
+
+/** Zookeeper global watcher for connection management
+ TODO: better connection management besides logs */
+static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
+ int state, const char *path,
+ void *watcher_ctx) {
+ if (type == ZOO_SESSION_EVENT) {
+ if (state == ZOO_EXPIRED_SESSION_STATE) {
+ gpr_log(GPR_ERROR, "Zookeeper session expired");
+ } else if (state == ZOO_AUTH_FAILED_STATE) {
+ gpr_log(GPR_ERROR, "Zookeeper authentication failed");
+ }
+ }
+}
+
+/** Zookeeper watcher triggered by changes to watched nodes
+ Once triggered, it tries to resolve again to get updated addresses */
+static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
+ const char *path, void *watcher_ctx) {
+ if (watcher_ctx != NULL) {
+ zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
+ if (state == ZOO_CONNECTED_STATE) {
+ gpr_mu_lock(&r->mu);
+ if (r->resolving == 0) {
+ zookeeper_start_resolving_locked(r);
+ }
+ gpr_mu_unlock(&r->mu);
+ }
+ }
+}
+
+/** Callback function after getting all resolved addresses
+ Creates a subchannel for each address */
+static void zookeeper_on_resolved(void *arg,
+ grpc_resolved_addresses *addresses) {
+ zookeeper_resolver *r = arg;
+ grpc_client_config *config = NULL;
+ grpc_subchannel **subchannels;
+ grpc_subchannel_args args;
+ grpc_lb_policy *lb_policy;
+ size_t i;
+ if (addresses != NULL) {
+ config = grpc_client_config_create();
+ subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
+ for (i = 0; i < addresses->naddrs; i++) {
+ memset(&args, 0, sizeof(args));
+ args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
+ args.addr_len = addresses->addrs[i].len;
+ subchannels[i] = grpc_subchannel_factory_create_subchannel(
+ r->subchannel_factory, &args);
+ }
+ lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs);
+ grpc_client_config_set_lb_policy(config, lb_policy);
+ GRPC_LB_POLICY_UNREF(lb_policy, "construction");
+ grpc_resolved_addresses_destroy(addresses);
+ gpr_free(subchannels);
+ }
+ gpr_mu_lock(&r->mu);
+ GPR_ASSERT(r->resolving == 1);
+ r->resolving = 0;
+ if (r->resolved_config != NULL) {
+ grpc_client_config_unref(r->resolved_config);
+ }
+ r->resolved_config = config;
+ r->resolved_version++;
+ zookeeper_maybe_finish_next_locked(r);
+ gpr_mu_unlock(&r->mu);
+
+ GRPC_RESOLVER_UNREF(&r->base, "zookeeper-resolving");
+}
+
+/** Callback function for each DNS resolved address */
+static void zookeeper_dns_resolved(void *arg,
+ grpc_resolved_addresses *addresses) {
+ size_t i;
+ zookeeper_resolver *r = arg;
+ int resolve_done = 0;
+
+ gpr_mu_lock(&r->mu);
+ r->resolved_num++;
+ r->resolved_addrs->addrs =
+ gpr_realloc(r->resolved_addrs->addrs,
+ sizeof(grpc_resolved_address) *
+ (r->resolved_addrs->naddrs + addresses->naddrs));
+ for (i = 0; i < addresses->naddrs; i++) {
+ memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
+ addresses->addrs[i].addr, addresses->addrs[i].len);
+ r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
+ addresses->addrs[i].len;
+ }
+
+ r->resolved_addrs->naddrs += addresses->naddrs;
+ grpc_resolved_addresses_destroy(addresses);
+
+ /** Wait for all addresses to be resolved */
+ resolve_done = (r->resolved_num == r->resolved_total);
+ gpr_mu_unlock(&r->mu);
+ if (resolve_done) {
+ zookeeper_on_resolved(r, r->resolved_addrs);
+ }
+}
+
+/** Parses JSON format address of a zookeeper node */
+static char *zookeeper_parse_address(const char *value, int value_len) {
+ grpc_json *json;
+ grpc_json *cur;
+ const char *host;
+ const char *port;
+ char *buffer;
+ char *address = NULL;
+
+ buffer = gpr_malloc(value_len);
+ memcpy(buffer, value, value_len);
+ json = grpc_json_parse_string_with_len(buffer, value_len);
+ if (json != NULL) {
+ host = NULL;
+ port = NULL;
+ for (cur = json->child; cur != NULL; cur = cur->next) {
+ if (!strcmp(cur->key, "host")) {
+ host = cur->value;
+ if (port != NULL) {
+ break;
+ }
+ } else if (!strcmp(cur->key, "port")) {
+ port = cur->value;
+ if (host != NULL) {
+ break;
+ }
+ }
+ }
+ if (host != NULL && port != NULL) {
+ gpr_asprintf(&address, "%s:%s", host, port);
+ }
+ grpc_json_destroy(json);
+ }
+ gpr_free(buffer);
+
+ return address;
+}
+
+static void zookeeper_get_children_node_completion(int rc, const char *value,
+ int value_len,
+ const struct Stat *stat,
+ const void *arg) {
+ char *address = NULL;
+ zookeeper_resolver *r = (zookeeper_resolver *)arg;
+ int resolve_done = 0;
+
+ if (rc != 0) {
+ gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
+ return;
+ }
+
+ address = zookeeper_parse_address(value, value_len);
+ if (address != NULL) {
+ /** Further resolves address by DNS */
+ grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+ gpr_free(address);
+ } else {
+ gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
+ gpr_mu_lock(&r->mu);
+ r->resolved_total--;
+ resolve_done = (r->resolved_num == r->resolved_total);
+ gpr_mu_unlock(&r->mu);
+ if (resolve_done) {
+ zookeeper_on_resolved(r, r->resolved_addrs);
+ }
+ }
+}
+
+static void zookeeper_get_children_completion(
+ int rc, const struct String_vector *children, const void *arg) {
+ char *path;
+ int status;
+ int i;
+ zookeeper_resolver *r = (zookeeper_resolver *)arg;
+
+ if (rc != 0) {
+ gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+ return;
+ }
+
+ if (children->count == 0) {
+ gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
+ return;
+ }
+
+ r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+ r->resolved_addrs->addrs = NULL;
+ r->resolved_addrs->naddrs = 0;
+ r->resolved_total = children->count;
+
+ /** TODO: Replace expensive heap allocation with stack
+ if we can get maximum length of zookeeper path */
+ for (i = 0; i < children->count; i++) {
+ gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
+ status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
+ zookeeper_get_children_node_completion, r);
+ gpr_free(path);
+ if (status != 0) {
+ gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
+ }
+ }
+}
+
+static void zookeeper_get_node_completion(int rc, const char *value,
+ int value_len,
+ const struct Stat *stat,
+ const void *arg) {
+ int status;
+ char *address = NULL;
+ zookeeper_resolver *r = (zookeeper_resolver *)arg;
+ r->resolved_addrs = NULL;
+ r->resolved_total = 0;
+ r->resolved_num = 0;
+
+ if (rc != 0) {
+ gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+ return;
+ }
+
+ /** If zookeeper node of path r->name does not have address
+ (i.e. service node), get its children */
+ address = zookeeper_parse_address(value, value_len);
+ if (address != NULL) {
+ r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+ r->resolved_addrs->addrs = NULL;
+ r->resolved_addrs->naddrs = 0;
+ r->resolved_total = 1;
+ /** Further resolves address by DNS */
+ grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+ gpr_free(address);
+ return;
+ }
+
+ status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
+ r, zookeeper_get_children_completion, r);
+ if (status != 0) {
+ gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+ }
+}
+
+static void zookeeper_resolve_address(zookeeper_resolver *r) {
+ int status;
+ status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
+ zookeeper_get_node_completion, r);
+ if (status != 0) {
+ gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+ }
+}
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
+ GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
+ GPR_ASSERT(r->resolving == 0);
+ r->resolving = 1;
+ zookeeper_resolve_address(r);
+}
+
+static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r) {
+ if (r->next_completion != NULL &&
+ r->resolved_version != r->published_version) {
+ *r->target_config = r->resolved_config;
+ if (r->resolved_config != NULL) {
+ grpc_client_config_ref(r->resolved_config);
+ }
+ grpc_iomgr_add_callback(r->next_completion);
+ r->next_completion = NULL;
+ r->published_version = r->resolved_version;
+ }
+}
+
+static void zookeeper_destroy(grpc_resolver *gr) {
+ zookeeper_resolver *r = (zookeeper_resolver *)gr;
+ gpr_mu_destroy(&r->mu);
+ if (r->resolved_config != NULL) {
+ grpc_client_config_unref(r->resolved_config);
+ }
+ grpc_subchannel_factory_unref(r->subchannel_factory);
+ gpr_free(r->name);
+ gpr_free(r);
+}
+
+static grpc_resolver *zookeeper_create(
+ grpc_uri *uri,
+ grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+ size_t num_subchannels),
+ grpc_subchannel_factory *subchannel_factory) {
+ zookeeper_resolver *r;
+ size_t length;
+ char *path = uri->path;
+
+ if (0 == strcmp(uri->authority, "")) {
+ gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
+ return NULL;
+ }
+
+ /** Removes the trailing slash if exists */
+ length = strlen(path);
+ if (length > 1 && path[length - 1] == '/') {
+ path[length - 1] = 0;
+ }
+
+ r = gpr_malloc(sizeof(zookeeper_resolver));
+ memset(r, 0, sizeof(*r));
+ gpr_ref_init(&r->refs, 1);
+ gpr_mu_init(&r->mu);
+ grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
+ r->name = gpr_strdup(path);
+
+ r->subchannel_factory = subchannel_factory;
+ r->lb_policy_factory = lb_policy_factory;
+ grpc_subchannel_factory_ref(subchannel_factory);
+
+ /** Initializes zookeeper client */
+ zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
+ r->zookeeper_handle = zookeeper_init(uri->authority, zookeeper_global_watcher,
+ GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
+ if (r->zookeeper_handle == NULL) {
+ gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
+ return NULL;
+ }
+
+ return &r->base;
+}
+
+static void zookeeper_plugin_init() {
+ grpc_register_resolver_type("zookeeper",
+ grpc_zookeeper_resolver_factory_create());
+}
+
+void grpc_zookeeper_register() {
+ grpc_register_plugin(zookeeper_plugin_init, NULL);
+}
+
+/*
+ * FACTORY
+ */
+
+static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
+
+static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
+
+static grpc_resolver *zookeeper_factory_create_resolver(
+ grpc_resolver_factory *factory, grpc_uri *uri,
+ grpc_subchannel_factory *subchannel_factory) {
+ return zookeeper_create(uri, grpc_create_pick_first_lb_policy,
+ subchannel_factory);
+}
+
+static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
+ zookeeper_factory_ref, zookeeper_factory_unref,
+ zookeeper_factory_create_resolver};
+static grpc_resolver_factory zookeeper_resolver_factory = {
+ &zookeeper_factory_vtable};
+
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() {
+ return &zookeeper_resolver_factory;
+}
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.h b/src/core/client_config/resolvers/zookeeper_resolver.h
new file mode 100644
index 0000000000..a6f002dd6d
--- /dev/null
+++ b/src/core/client_config/resolvers/zookeeper_resolver.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
+
+#include "src/core/client_config/resolver_factory.h"
+
+/** Create a zookeeper resolver factory */
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
index d1cd33b2af..2e36c69134 100644
--- a/src/core/client_config/subchannel.h
+++ b/src/core/client_config/subchannel.h
@@ -91,8 +91,10 @@ void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel,
grpc_connectivity_state *state,
grpc_iomgr_closure *notify);
+/** express interest in \a channel's activities through \a pollset. */
void grpc_subchannel_add_interested_party(grpc_subchannel *channel,
grpc_pollset *pollset);
+/** stop following \a channel's activity through \a pollset. */
void grpc_subchannel_del_interested_party(grpc_subchannel *channel,
grpc_pollset *pollset);
diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c
index 7dc6d99ebe..585e465fa4 100644
--- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c
+++ b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c
@@ -35,9 +35,9 @@
#include "src/core/client_config/subchannel_factory_decorators/merge_channel_args.h"
grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg(
- grpc_subchannel_factory *input, const grpc_arg *arg) {
- grpc_channel_args args;
- args.num_args = 1;
- args.args = (grpc_arg *)arg;
- return grpc_subchannel_factory_merge_channel_args(input, &args);
+ grpc_subchannel_factory *input, const grpc_arg *arg) {
+ grpc_channel_args args;
+ args.num_args = 1;
+ args.args = (grpc_arg *)arg;
+ return grpc_subchannel_factory_merge_channel_args(input, &args);
}
diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
index 1937623374..8457294000 100644
--- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
+++ b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
@@ -40,6 +40,7 @@
channel_args by adding a new argument; ownership of input, arg is retained
by the caller. */
grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg(
- grpc_subchannel_factory *input, const grpc_arg *arg);
+ grpc_subchannel_factory *input, const grpc_arg *arg);
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H */
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H \
+ */
diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
index 7e028857ac..c1b5507fde 100644
--- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
+++ b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
@@ -50,7 +50,7 @@ static void merge_args_factory_ref(grpc_subchannel_factory *scf) {
static void merge_args_factory_unref(grpc_subchannel_factory *scf) {
merge_args_factory *f = (merge_args_factory *)scf;
if (gpr_unref(&f->refs)) {
- grpc_subchannel_factory_unref(f->wrapped);
+ grpc_subchannel_factory_unref(f->wrapped);
grpc_channel_args_destroy(f->merge_args);
gpr_free(f);
}
@@ -73,7 +73,7 @@ static const grpc_subchannel_factory_vtable merge_args_factory_vtable = {
merge_args_factory_create_subchannel};
grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args(
- grpc_subchannel_factory *input, const grpc_channel_args *args) {
+ grpc_subchannel_factory *input, const grpc_channel_args *args) {
merge_args_factory *f = gpr_malloc(sizeof(*f));
f->base.vtable = &merge_args_factory_vtable;
gpr_ref_init(&f->refs, 1);
diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
index 73a03b752f..f4757f0650 100644
--- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
+++ b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
@@ -40,6 +40,7 @@
channel_args by adding a new argument; ownership of input, args is retained
by the caller. */
grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args(
- grpc_subchannel_factory *input, const grpc_channel_args *args);
+ grpc_subchannel_factory *input, const grpc_channel_args *args);
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H */
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H \
+ */
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index e426241d0a..6ed6dbe93f 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -35,13 +35,20 @@
#include <string.h>
#include <grpc/compression.h>
-int grpc_compression_algorithm_parse(const char* name,
+int grpc_compression_algorithm_parse(const char *name, size_t name_length,
grpc_compression_algorithm *algorithm) {
- if (strcmp(name, "none") == 0) {
+ /* we use strncmp not only because it's safer (even though in this case it
+ * doesn't matter, given that we are comparing against string literals, but
+ * because this way we needn't have "name" nil-terminated (useful for slice
+ * data, for example) */
+ if (name_length == 0) {
+ return 0;
+ }
+ if (strncmp(name, "identity", name_length) == 0) {
*algorithm = GRPC_COMPRESS_NONE;
- } else if (strcmp(name, "gzip") == 0) {
+ } else if (strncmp(name, "gzip", name_length) == 0) {
*algorithm = GRPC_COMPRESS_GZIP;
- } else if (strcmp(name, "deflate") == 0) {
+ } else if (strncmp(name, "deflate", name_length) == 0) {
*algorithm = GRPC_COMPRESS_DEFLATE;
} else {
return 0;
@@ -53,7 +60,7 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
char **name) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
- *name = "none";
+ *name = "identity";
break;
case GRPC_COMPRESS_DEFLATE:
*name = "deflate";
diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c
index b53dfe804b..1014b1f4db 100644
--- a/src/core/debug/trace.c
+++ b/src/core/debug/trace.c
@@ -61,8 +61,8 @@ static void add(const char *beg, const char *end, char ***ss, size_t *ns) {
size_t np = n + 1;
char *s = gpr_malloc(end - beg + 1);
memcpy(s, beg, end - beg);
- s[end-beg] = 0;
- *ss = gpr_realloc(*ss, sizeof(char**) * np);
+ s[end - beg] = 0;
+ *ss = gpr_realloc(*ss, sizeof(char **) * np);
(*ss)[n] = s;
*ns = np;
}
@@ -73,7 +73,7 @@ static void split(const char *s, char ***ss, size_t *ns) {
add(s, s + strlen(s), ss, ns);
} else {
add(s, c, ss, ns);
- split(c+1, ss, ns);
+ split(c + 1, ss, ns);
}
}
@@ -125,7 +125,7 @@ int grpc_tracer_set_enabled(const char *name, int enabled) {
}
if (!found) {
gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name);
- return 0; /* early return */
+ return 0; /* early return */
}
}
return 1;
diff --git a/src/core/debug/trace.h b/src/core/debug/trace.h
index fc8615bc69..dc5875976e 100644
--- a/src/core/debug/trace.h
+++ b/src/core/debug/trace.h
@@ -40,4 +40,4 @@ void grpc_register_tracer(const char *name, int *flag);
void grpc_tracer_init(const char *env_var_name);
void grpc_tracer_shutdown(void);
-#endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */
+#endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */
diff --git a/src/core/httpcli/format_request.c b/src/core/httpcli/format_request.c
index e875423e87..6189fce86b 100644
--- a/src/core/httpcli/format_request.c
+++ b/src/core/httpcli/format_request.c
@@ -43,7 +43,8 @@
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
-static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *buf) {
+static void fill_common_header(const grpc_httpcli_request *request,
+ gpr_strvec *buf) {
size_t i;
gpr_strvec_add(buf, gpr_strdup(request->path));
gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n"));
@@ -52,7 +53,8 @@ static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *
gpr_strvec_add(buf, gpr_strdup(request->host));
gpr_strvec_add(buf, gpr_strdup("\r\n"));
gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n"));
- gpr_strvec_add(buf, gpr_strdup("User-Agent: "GRPC_HTTPCLI_USER_AGENT"\r\n"));
+ gpr_strvec_add(buf,
+ gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"));
/* user supplied headers */
for (i = 0; i < request->hdr_count; i++) {
gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key));
diff --git a/src/core/httpcli/format_request.h b/src/core/httpcli/format_request.h
index 8bfb20bfd0..c8dc8f7d4e 100644
--- a/src/core/httpcli/format_request.h
+++ b/src/core/httpcli/format_request.h
@@ -42,4 +42,4 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
const char *body_bytes,
size_t body_size);
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */
+#endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */
diff --git a/src/core/httpcli/parser.h b/src/core/httpcli/parser.h
index 71280e7479..3fbb4c7479 100644
--- a/src/core/httpcli/parser.h
+++ b/src/core/httpcli/parser.h
@@ -61,4 +61,4 @@ void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser);
int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice);
int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser);
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */
+#endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */
diff --git a/src/core/iomgr/alarm.c b/src/core/iomgr/alarm.c
index 68d33b9cf6..ddb30dc4bb 100644
--- a/src/core/iomgr/alarm.c
+++ b/src/core/iomgr/alarm.c
@@ -105,8 +105,7 @@ void grpc_alarm_list_init(gpr_timespec now) {
void grpc_alarm_list_shutdown(void) {
int i;
- while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL,
- 0))
+ while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL, 0))
;
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
@@ -362,7 +361,7 @@ static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now,
int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next) {
GPR_ASSERT(now.clock_type == g_clock_type);
return run_some_expired_alarms(
- drop_mu, now, next,
+ drop_mu, now, next,
gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
}
diff --git a/src/core/iomgr/alarm.h b/src/core/iomgr/alarm.h
index c067a0b8a3..4a13527e64 100644
--- a/src/core/iomgr/alarm.h
+++ b/src/core/iomgr/alarm.h
@@ -86,4 +86,4 @@ void grpc_alarm_init(grpc_alarm *alarm, gpr_timespec deadline,
Requires: cancel() must happen after add() on a given alarm */
void grpc_alarm_cancel(grpc_alarm *alarm);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_H */
diff --git a/src/core/iomgr/alarm_heap.c b/src/core/iomgr/alarm_heap.c
index d912178fda..daed251982 100644
--- a/src/core/iomgr/alarm_heap.c
+++ b/src/core/iomgr/alarm_heap.c
@@ -66,11 +66,11 @@ static void adjust_downwards(grpc_alarm **first, int i, int length,
int next_i;
if (left_child >= length) break;
right_child = left_child + 1;
- next_i =
- right_child < length && gpr_time_cmp(first[left_child]->deadline,
- first[right_child]->deadline) < 0
- ? right_child
- : left_child;
+ next_i = right_child < length &&
+ gpr_time_cmp(first[left_child]->deadline,
+ first[right_child]->deadline) < 0
+ ? right_child
+ : left_child;
if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break;
first[i] = first[next_i];
first[i]->heap_index = i;
diff --git a/src/core/iomgr/alarm_heap.h b/src/core/iomgr/alarm_heap.h
index c5adfc6d31..60db6c991b 100644
--- a/src/core/iomgr/alarm_heap.h
+++ b/src/core/iomgr/alarm_heap.h
@@ -54,4 +54,4 @@ void grpc_alarm_heap_pop(grpc_alarm_heap *heap);
int grpc_alarm_heap_is_empty(grpc_alarm_heap *heap);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H */
diff --git a/src/core/iomgr/alarm_internal.h b/src/core/iomgr/alarm_internal.h
index 0268a01bad..e9f98a3444 100644
--- a/src/core/iomgr/alarm_internal.h
+++ b/src/core/iomgr/alarm_internal.h
@@ -59,4 +59,4 @@ gpr_timespec grpc_alarm_list_next_timeout(void);
void grpc_kick_poller(void);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H */
diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c
index 744fe7656c..8ee14bce9b 100644
--- a/src/core/iomgr/endpoint.c
+++ b/src/core/iomgr/endpoint.c
@@ -50,7 +50,8 @@ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
ep->vtable->add_to_pollset(ep, pollset);
}
-void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
+void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep,
+ grpc_pollset_set *pollset_set) {
ep->vtable->add_to_pollset_set(ep, pollset_set);
}
diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h
index a2216925f9..ea92a500e8 100644
--- a/src/core/iomgr/endpoint.h
+++ b/src/core/iomgr/endpoint.h
@@ -103,10 +103,11 @@ void grpc_endpoint_destroy(grpc_endpoint *ep);
/* Add an endpoint to a pollset, so that when the pollset is polled, events from
this endpoint are considered */
void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset);
-void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set);
+void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep,
+ grpc_pollset_set *pollset_set);
struct grpc_endpoint {
const grpc_endpoint_vtable *vtable;
};
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */
diff --git a/src/core/iomgr/endpoint_pair.h b/src/core/iomgr/endpoint_pair.h
index 25087be0c7..095ec5fcc9 100644
--- a/src/core/iomgr/endpoint_pair.h
+++ b/src/core/iomgr/endpoint_pair.h
@@ -44,4 +44,4 @@ typedef struct {
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
size_t read_slice_size);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c
index e8295df8b3..db9d092dca 100644
--- a/src/core/iomgr/endpoint_pair_windows.c
+++ b/src/core/iomgr/endpoint_pair_windows.c
@@ -52,21 +52,26 @@ static void create_sockets(SOCKET sv[2]) {
SOCKADDR_IN addr;
int addr_len = sizeof(addr);
- lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+ WSA_FLAG_OVERLAPPED);
GPR_ASSERT(lst_sock != INVALID_SOCKET);
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_family = AF_INET;
- GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR);
+ GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) !=
+ SOCKET_ERROR);
GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
- GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) != SOCKET_ERROR);
+ GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) !=
+ SOCKET_ERROR);
- cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+ WSA_FLAG_OVERLAPPED);
GPR_ASSERT(cli_sock != INVALID_SOCKET);
- GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL, NULL, NULL) == 0);
- svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len);
+ GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL,
+ NULL, NULL, NULL) == 0);
+ svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len);
GPR_ASSERT(svr_sock != INVALID_SOCKET);
closesocket(lst_sock);
@@ -77,7 +82,8 @@ static void create_sockets(SOCKET sv[2]) {
sv[0] = svr_sock;
}
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+ size_t read_slice_size) {
SOCKET sv[2];
grpc_endpoint_pair p;
create_sockets(sv);
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 8741241fb8..09a457dd9a 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -65,18 +65,17 @@ static void do_iocp_work() {
LPOVERLAPPED overlapped;
grpc_winsocket *socket;
grpc_winsocket_callback_info *info;
- void(*f)(void *, int) = NULL;
+ void (*f)(void *, int) = NULL;
void *opaque = NULL;
- success = GetQueuedCompletionStatus(g_iocp, &bytes,
- &completion_key, &overlapped,
- INFINITE);
+ success = GetQueuedCompletionStatus(g_iocp, &bytes, &completion_key,
+ &overlapped, INFINITE);
/* success = 0 and overlapped = NULL means the deadline got attained.
Which is impossible. since our wait time is +inf */
GPR_ASSERT(success || overlapped);
GPR_ASSERT(completion_key && overlapped);
if (overlapped == &g_iocp_custom_overlap) {
gpr_atm_full_fetch_add(&g_custom_events, -1);
- if (completion_key == (ULONG_PTR) &g_iocp_kick_token) {
+ if (completion_key == (ULONG_PTR)&g_iocp_kick_token) {
/* We were awoken from a kick. */
return;
}
@@ -84,7 +83,7 @@ static void do_iocp_work() {
abort();
}
- socket = (grpc_winsocket*) completion_key;
+ socket = (grpc_winsocket *)completion_key;
if (overlapped == &socket->write_info.overlapped) {
info = &socket->write_info;
} else if (overlapped == &socket->read_info.overlapped) {
@@ -121,8 +120,7 @@ static void do_iocp_work() {
}
static void iocp_loop(void *p) {
- while (gpr_atm_acq_load(&g_orphans) ||
- gpr_atm_acq_load(&g_custom_events) ||
+ while (gpr_atm_acq_load(&g_orphans) || gpr_atm_acq_load(&g_custom_events) ||
!gpr_event_get(&g_shutdown_iocp)) {
grpc_maybe_call_delayed_callbacks(NULL, 1);
do_iocp_work();
@@ -134,8 +132,8 @@ static void iocp_loop(void *p) {
void grpc_iocp_init(void) {
gpr_thd_id id;
- g_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
- NULL, (ULONG_PTR)NULL, 0);
+ g_iocp =
+ CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0);
GPR_ASSERT(g_iocp);
gpr_event_init(&g_iocp_done);
@@ -147,8 +145,7 @@ void grpc_iocp_kick(void) {
BOOL success;
gpr_atm_full_fetch_add(&g_custom_events, 1);
- success = PostQueuedCompletionStatus(g_iocp, 0,
- (ULONG_PTR) &g_iocp_kick_token,
+ success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token,
&g_iocp_custom_overlap);
GPR_ASSERT(success);
}
@@ -165,8 +162,8 @@ void grpc_iocp_shutdown(void) {
void grpc_iocp_add_socket(grpc_winsocket *socket) {
HANDLE ret;
if (socket->added_to_iocp) return;
- ret = CreateIoCompletionPort((HANDLE)socket->socket,
- g_iocp, (gpr_uintptr) socket, 0);
+ ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp,
+ (gpr_uintptr)socket, 0);
if (!ret) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message);
@@ -189,7 +186,7 @@ void grpc_iocp_socket_orphan(grpc_winsocket *socket) {
the callback now.
-) The IOCP hasn't completed yet, and we're queuing it for later. */
static void socket_notify_on_iocp(grpc_winsocket *socket,
- void(*cb)(void *, int), void *opaque,
+ void (*cb)(void *, int), void *opaque,
grpc_winsocket_callback_info *info) {
int run_now = 0;
GPR_ASSERT(!info->cb);
@@ -206,13 +203,13 @@ static void socket_notify_on_iocp(grpc_winsocket *socket,
}
void grpc_socket_notify_on_write(grpc_winsocket *socket,
- void(*cb)(void *, int), void *opaque) {
+ void (*cb)(void *, int), void *opaque) {
socket_notify_on_iocp(socket, cb, opaque, &socket->write_info);
}
-void grpc_socket_notify_on_read(grpc_winsocket *socket,
- void(*cb)(void *, int), void *opaque) {
+void grpc_socket_notify_on_read(grpc_winsocket *socket, void (*cb)(void *, int),
+ void *opaque) {
socket_notify_on_iocp(socket, cb, opaque, &socket->read_info);
}
-#endif /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 9df6476917..ee3847a229 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -44,10 +44,10 @@ void grpc_iocp_shutdown(void);
void grpc_iocp_add_socket(grpc_winsocket *);
void grpc_iocp_socket_orphan(grpc_winsocket *);
-void grpc_socket_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success),
- void *opaque);
+void grpc_socket_notify_on_write(grpc_winsocket *,
+ void (*cb)(void *, int success), void *opaque);
-void grpc_socket_notify_on_read(grpc_winsocket *, void(*cb)(void *, int success),
- void *opaque);
+void grpc_socket_notify_on_read(grpc_winsocket *,
+ void (*cb)(void *, int success), void *opaque);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/iomgr/iomgr.h b/src/core/iomgr/iomgr.h
index 6d4a82917b..261c17366a 100644
--- a/src/core/iomgr/iomgr.h
+++ b/src/core/iomgr/iomgr.h
@@ -77,4 +77,4 @@ void grpc_iomgr_add_callback(grpc_iomgr_closure *closure);
argument. */
void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */
diff --git a/src/core/iomgr/iomgr_internal.h b/src/core/iomgr/iomgr_internal.h
index 6c1e0e1799..4cec973ba0 100644
--- a/src/core/iomgr/iomgr_internal.h
+++ b/src/core/iomgr/iomgr_internal.h
@@ -52,4 +52,4 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object *obj);
void grpc_iomgr_platform_init(void);
void grpc_iomgr_platform_shutdown(void);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */
diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c
index 758ae77b86..2425e59941 100644
--- a/src/core/iomgr/iomgr_posix.c
+++ b/src/core/iomgr/iomgr_posix.c
@@ -51,4 +51,4 @@ void grpc_iomgr_platform_shutdown(void) {
grpc_fd_global_shutdown();
}
-#endif /* GRPC_POSIX_SOCKET */
+#endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/iomgr/iomgr_posix.h b/src/core/iomgr/iomgr_posix.h
index a404f6433e..716fedb636 100644
--- a/src/core/iomgr/iomgr_posix.h
+++ b/src/core/iomgr/iomgr_posix.h
@@ -39,4 +39,4 @@
void grpc_pollset_global_init(void);
void grpc_pollset_global_shutdown(void);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */
diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c
index 74cd5a829b..b49cb87e97 100644
--- a/src/core/iomgr/iomgr_windows.c
+++ b/src/core/iomgr/iomgr_windows.c
@@ -68,4 +68,4 @@ void grpc_iomgr_platform_shutdown(void) {
winsock_shutdown();
}
-#endif /* GRPC_WINSOCK_SOCKET */
+#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index 1320c64579..5ea9dd2101 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -234,8 +234,7 @@ static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
}
static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
- multipoll_with_epoll_pollset_add_fd,
- multipoll_with_epoll_pollset_del_fd,
+ multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd,
multipoll_with_epoll_pollset_maybe_work,
multipoll_with_epoll_pollset_finish_shutdown,
multipoll_with_epoll_pollset_destroy};
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index b5b2d7534d..001fcecf76 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -74,7 +74,7 @@ static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
}
h->fds[h->fd_count++] = fd;
GRPC_FD_REF(fd, "multipoller");
-exit:
+exit:
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
@@ -202,8 +202,7 @@ static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
}
static const grpc_pollset_vtable multipoll_with_poll_pollset = {
- multipoll_with_poll_pollset_add_fd,
- multipoll_with_poll_pollset_del_fd,
+ multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd,
multipoll_with_poll_pollset_maybe_work,
multipoll_with_poll_pollset_finish_shutdown,
multipoll_with_poll_pollset_destroy};
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index d3a9193af1..a01f9ff727 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -140,10 +140,10 @@ void grpc_pollset_init(grpc_pollset *pollset) {
void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
gpr_mu_lock(&pollset->mu);
pollset->vtable->add_fd(pollset, fd, 1);
- /* the following (enabled only in debug) will reacquire and then release
- our lock - meaning that if the unlocking flag passed to del_fd above is
- not respected, the code will deadlock (in a way that we have a chance of
- debugging) */
+/* the following (enabled only in debug) will reacquire and then release
+ our lock - meaning that if the unlocking flag passed to del_fd above is
+ not respected, the code will deadlock (in a way that we have a chance of
+ debugging) */
#ifndef NDEBUG
gpr_mu_lock(&pollset->mu);
gpr_mu_unlock(&pollset->mu);
@@ -153,10 +153,10 @@ void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
gpr_mu_lock(&pollset->mu);
pollset->vtable->del_fd(pollset, fd, 1);
- /* the following (enabled only in debug) will reacquire and then release
- our lock - meaning that if the unlocking flag passed to del_fd above is
- not respected, the code will deadlock (in a way that we have a chance of
- debugging) */
+/* the following (enabled only in debug) will reacquire and then release
+ our lock - meaning that if the unlocking flag passed to del_fd above is
+ not respected, the code will deadlock (in a way that we have a chance of
+ debugging) */
#ifndef NDEBUG
gpr_mu_lock(&pollset->mu);
gpr_mu_unlock(&pollset->mu);
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index 1c1b736193..a3ea353de6 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -102,7 +102,8 @@ void grpc_kick_drain(grpc_pollset *p);
- longer than a millisecond polls are rounded up to the next nearest
millisecond to avoid spinning
- infinite timeouts are converted to -1 */
-int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now);
+int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
+ gpr_timespec now);
/* turn a pollset into a multipoller: platform specific */
typedef void (*grpc_platform_become_multipoller_type)(grpc_pollset *pollset,
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index 22dc5891c3..8710395ab3 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -56,8 +56,7 @@ static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) {
grpc_pollset_worker *w = p->root_worker.next;
remove_worker(p, w);
return w;
- }
- else {
+ } else {
return NULL;
}
}
@@ -100,7 +99,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
gpr_mu_destroy(&pollset->mu);
}
-int grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline) {
+int grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker,
+ gpr_timespec deadline) {
gpr_timespec now;
int added_worker = 0;
now = gpr_now(GPR_CLOCK_MONOTONIC);
@@ -134,8 +134,8 @@ void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
if (specific_worker != NULL) {
if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
for (specific_worker = p->root_worker.next;
- specific_worker != &p->root_worker;
- specific_worker = specific_worker->next) {
+ specific_worker != &p->root_worker;
+ specific_worker = specific_worker->next) {
gpr_cv_signal(&specific_worker->cv);
}
p->kicked_without_pollers = 1;
diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h
index 8f1d7a22bb..cc1bd428b0 100644
--- a/src/core/iomgr/resolve_address.h
+++ b/src/core/iomgr/resolve_address.h
@@ -66,4 +66,4 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
grpc_resolved_addresses *grpc_blocking_resolve_address(
const char *addr, const char *default_port);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c
index dbf884c769..ce6972b797 100644
--- a/src/core/iomgr/resolve_address_posix.c
+++ b/src/core/iomgr/resolve_address_posix.c
@@ -105,10 +105,7 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
s = getaddrinfo(host, port, &hints, &result);
if (s != 0) {
/* Retry if well-known service name is recognized */
- char *svc[][2] = {
- {"http", "80"},
- {"https", "443"}
- };
+ char *svc[][2] = {{"http", "80"}, {"https", "443"}};
int i;
for (i = 0; i < (int)(sizeof(svc) / sizeof(svc[0])); i++) {
if (strcmp(port, svc[i][0]) == 0) {
diff --git a/src/core/iomgr/sockaddr.h b/src/core/iomgr/sockaddr.h
index 7528db73b8..e41e1ec6b4 100644
--- a/src/core/iomgr/sockaddr.h
+++ b/src/core/iomgr/sockaddr.h
@@ -44,4 +44,4 @@
#include "src/core/iomgr/sockaddr_posix.h"
#endif
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */
diff --git a/src/core/iomgr/sockaddr_posix.h b/src/core/iomgr/sockaddr_posix.h
index 2a3d932f70..388abb3306 100644
--- a/src/core/iomgr/sockaddr_posix.h
+++ b/src/core/iomgr/sockaddr_posix.h
@@ -41,4 +41,4 @@
#include <netdb.h>
#include <unistd.h>
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */
diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c
index 65ec1f94ac..efdc480365 100644
--- a/src/core/iomgr/sockaddr_utils.c
+++ b/src/core/iomgr/sockaddr_utils.c
@@ -206,7 +206,8 @@ int grpc_sockaddr_get_port(const struct sockaddr *addr) {
case AF_UNIX:
return 1;
default:
- gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family);
+ gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port",
+ addr->sa_family);
return 0;
}
}
@@ -220,7 +221,8 @@ int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) {
((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
return 1;
default:
- gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", addr->sa_family);
+ gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port",
+ addr->sa_family);
return 0;
}
}
diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h
index 99f1ed54da..6f7a279900 100644
--- a/src/core/iomgr/sockaddr_utils.h
+++ b/src/core/iomgr/sockaddr_utils.h
@@ -86,4 +86,4 @@ int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
char *grpc_sockaddr_to_uri(const struct sockaddr *addr);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */
diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h
index be55db805a..fe2be99145 100644
--- a/src/core/iomgr/sockaddr_win32.h
+++ b/src/core/iomgr/sockaddr_win32.h
@@ -43,4 +43,4 @@
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#endif
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */
diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h
index d2a315b462..d330d1986e 100644
--- a/src/core/iomgr/socket_utils_posix.h
+++ b/src/core/iomgr/socket_utils_posix.h
@@ -110,4 +110,4 @@ extern int grpc_forbid_dualstack_sockets_for_testing;
int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
int protocol, grpc_dualstack_mode *dsmode);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index f6ddfff0ad..7d8421376b 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -106,4 +106,4 @@ void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
gpr_free(winsocket);
}
-#endif /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index 346fde8edd..ecf2530173 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -54,7 +54,7 @@ typedef struct grpc_winsocket_callback_info {
OVERLAPPED overlapped;
/* The callback information for the pending operation. May be empty if the
caller hasn't registered a callback yet. */
- void(*cb)(void *opaque, int success);
+ void (*cb)(void *opaque, int success);
void *opaque;
/* A boolean to describe if the IO Completion Port got a notification for
that operation. This will happen if the operation completed before the
@@ -118,4 +118,4 @@ void grpc_winsocket_orphan(grpc_winsocket *socket);
or by grpc_winsocket_orphan if there's no pending operation. */
void grpc_winsocket_destroy(grpc_winsocket *socket);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/iomgr/tcp_client.h b/src/core/iomgr/tcp_client.h
index 0fa08b52b0..8ad9b818e1 100644
--- a/src/core/iomgr/tcp_client.h
+++ b/src/core/iomgr/tcp_client.h
@@ -41,7 +41,7 @@
/* Asynchronously connect to an address (specified as (addr, len)), and call
cb with arg and the completed connection when done (or call cb with arg and
- NULL on failure).
+ NULL on failure).
interested_parties points to a set of pollsets that would be interested
in this connection being established (in order to continue their work) */
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index 9572ce5980..66027f87a0 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -264,7 +264,8 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
ac->write_closure.cb_arg = ac;
gpr_mu_lock(&ac->mu);
- grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+ grpc_alarm_init(&ac->alarm,
+ gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
gpr_mu_unlock(&ac->mu);
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 24fee0596f..360e6ebd8c 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -572,7 +572,8 @@ static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_pollset_add_fd(pollset, tcp->em_fd);
}
-static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
+static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep,
+ grpc_pollset_set *pollset_set) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_pollset_set_add_fd(pollset_set, tcp->em_fd);
}
diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h
index d752feaeea..40b3ae2679 100644
--- a/src/core/iomgr/tcp_posix.h
+++ b/src/core/iomgr/tcp_posix.h
@@ -56,4 +56,4 @@ extern int grpc_tcp_trace;
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
const char *peer_string);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 0adbe9507c..d0478d3604 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -79,7 +79,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
- /* number of iomgr callbacks that have been explicitly scheduled during shutdown */
+ /* number of iomgr callbacks that have been explicitly scheduled during
+ * shutdown */
int iomgr_callbacks_pending;
/* all listening ports */
@@ -292,7 +293,7 @@ static void on_accept(void *arg, int from_iocp) {
and act accordingly. */
transfered_bytes = 0;
wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
- &transfered_bytes, FALSE, &flags);
+ &transfered_bytes, FALSE, &flags);
if (!wsa_success) {
if (sp->shutting_down) {
/* During the shutdown case, we ARE expecting an error. So that's well,
@@ -309,16 +310,15 @@ static void on_accept(void *arg, int from_iocp) {
if (!sp->shutting_down) {
peer_name_string = NULL;
err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- (char *)&sp->socket->socket,
- sizeof(sp->socket->socket));
+ (char *)&sp->socket->socket, sizeof(sp->socket->socket));
if (err) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
gpr_free(utf8_message);
}
- err = getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len);
+ err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
if (!err) {
- peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name);
+ peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
} else {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 89aa741470..123f46d71d 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -55,24 +55,22 @@ static int set_non_block(SOCKET sock) {
int status;
unsigned long param = 1;
DWORD ret;
- status = WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret,
- NULL, NULL);
+ status =
+ WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret, NULL, NULL);
return status == 0;
}
static int set_dualstack(SOCKET sock) {
int status;
unsigned long param = 0;
- status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (const char *) &param, sizeof(param));
+ status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
+ sizeof(param));
return status == 0;
}
int grpc_tcp_prepare_socket(SOCKET sock) {
- if (!set_non_block(sock))
- return 0;
- if (!set_dualstack(sock))
- return 0;
+ if (!set_non_block(sock)) return 0;
+ if (!set_dualstack(sock)) return 0;
return 1;
}
@@ -100,9 +98,7 @@ typedef struct grpc_tcp {
char *peer_string;
} grpc_tcp;
-static void tcp_ref(grpc_tcp *tcp) {
- gpr_ref(&tcp->refcount);
-}
+static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
static void tcp_unref(grpc_tcp *tcp) {
if (gpr_unref(&tcp->refcount)) {
@@ -116,7 +112,7 @@ static void tcp_unref(grpc_tcp *tcp) {
/* Asynchronous callback from the IOCP, or the background thread. */
static void on_read(void *tcpp, int from_iocp) {
- grpc_tcp *tcp = (grpc_tcp *) tcpp;
+ grpc_tcp *tcp = (grpc_tcp *)tcpp;
grpc_winsocket *socket = tcp->socket;
gpr_slice sub;
gpr_slice *slice = NULL;
@@ -175,9 +171,9 @@ static void on_read(void *tcpp, int from_iocp) {
cb(opaque, slice, nslices, status);
}
-static void win_notify_on_read(grpc_endpoint *ep,
- grpc_endpoint_read_cb cb, void *arg) {
- grpc_tcp *tcp = (grpc_tcp *) ep;
+static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
+ void *arg) {
+ grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->read_info;
int status;
@@ -201,8 +197,8 @@ static void win_notify_on_read(grpc_endpoint *ep,
buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
/* First let's try a synchronous, non-blocking read. */
- status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
- NULL, NULL);
+ status =
+ WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
/* Did we get data immediately ? Yay. */
@@ -232,7 +228,7 @@ static void win_notify_on_read(grpc_endpoint *ep,
/* Asynchronous callback from the IOCP, or the background thread. */
static void on_write(void *tcpp, int from_iocp) {
- grpc_tcp *tcp = (grpc_tcp *) tcpp;
+ grpc_tcp *tcp = (grpc_tcp *)tcpp;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->write_info;
grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
@@ -286,7 +282,7 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
gpr_slice *slices, size_t nslices,
grpc_endpoint_write_cb cb,
void *arg) {
- grpc_tcp *tcp = (grpc_tcp *) ep;
+ grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *socket = tcp->socket;
grpc_winsocket_callback_info *info = &socket->write_info;
unsigned i;
@@ -309,7 +305,7 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
- buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
+ buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
allocated = buffers;
}
@@ -370,15 +366,15 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
grpc_tcp *tcp;
- (void) ps;
- tcp = (grpc_tcp *) ep;
+ (void)ps;
+ tcp = (grpc_tcp *)ep;
grpc_iocp_add_socket(tcp->socket);
}
static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
grpc_tcp *tcp;
- (void) pss;
- tcp = (grpc_tcp *) ep;
+ (void)pss;
+ tcp = (grpc_tcp *)ep;
grpc_iocp_add_socket(tcp->socket);
}
@@ -389,7 +385,7 @@ static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
callback will happen from another thread, so we need to protect against
concurrent access of the data structure in that regard. */
static void win_shutdown(grpc_endpoint *ep) {
- grpc_tcp *tcp = (grpc_tcp *) ep;
+ grpc_tcp *tcp = (grpc_tcp *)ep;
int extra_refs = 0;
gpr_mu_lock(&tcp->mu);
/* At that point, what may happen is that we're already inside the IOCP
@@ -401,7 +397,7 @@ static void win_shutdown(grpc_endpoint *ep) {
}
static void win_destroy(grpc_endpoint *ep) {
- grpc_tcp *tcp = (grpc_tcp *) ep;
+ grpc_tcp *tcp = (grpc_tcp *)ep;
tcp_unref(tcp);
}
@@ -410,13 +406,12 @@ static char *win_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string);
}
-static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write,
- win_add_to_pollset, win_add_to_pollset_set,
- win_shutdown, win_destroy,
- win_get_peer};
+static grpc_endpoint_vtable vtable = {
+ win_notify_on_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
+ win_shutdown, win_destroy, win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
- grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
+ grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
memset(tcp, 0, sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
tcp->socket = socket;
@@ -427,4 +422,4 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
return &tcp->base;
}
-#endif /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h
index 7e301db250..deb3e48293 100644
--- a/src/core/iomgr/tcp_windows.h
+++ b/src/core/iomgr/tcp_windows.h
@@ -54,4 +54,4 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string);
int grpc_tcp_prepare_socket(SOCKET sock);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */
diff --git a/src/core/iomgr/time_averaged_stats.h b/src/core/iomgr/time_averaged_stats.h
index 13894b2640..e6dec1b4cd 100644
--- a/src/core/iomgr/time_averaged_stats.h
+++ b/src/core/iomgr/time_averaged_stats.h
@@ -85,4 +85,4 @@ void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats *stats,
value. */
double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats *stats);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
new file mode 100644
index 0000000000..16482c08f7
--- /dev/null
+++ b/src/core/iomgr/udp_server.c
@@ -0,0 +1,438 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/iomgr/udp_server.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "src/core/iomgr/fd_posix.h"
+#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/iomgr/socket_utils_posix.h"
+#include "src/core/support/string.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#define INIT_PORT_CAP 2
+
+/* one listening port */
+typedef struct {
+ int fd;
+ grpc_fd *emfd;
+ grpc_udp_server *server;
+ union {
+ gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE];
+ struct sockaddr sockaddr;
+ struct sockaddr_un un;
+ } addr;
+ int addr_len;
+ grpc_iomgr_closure read_closure;
+ grpc_iomgr_closure destroyed_closure;
+ grpc_udp_server_read_cb read_cb;
+} server_port;
+
+static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
+ struct stat st;
+
+ if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
+ unlink(un->sun_path);
+ }
+}
+
+/* the overall server */
+struct grpc_udp_server {
+ grpc_udp_server_cb cb;
+ void *cb_arg;
+
+ gpr_mu mu;
+ gpr_cv cv;
+
+ /* 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? (boolean) */
+ int shutdown;
+
+ /* all listening ports */
+ server_port *ports;
+ size_t nports;
+ size_t port_capacity;
+
+ /* shutdown callback */
+ void (*shutdown_complete)(void *);
+ void *shutdown_complete_arg;
+
+ /* all pollsets interested in new connections */
+ grpc_pollset **pollsets;
+ /* number of pollsets in the pollsets array */
+ size_t pollset_count;
+};
+
+grpc_udp_server *grpc_udp_server_create(void) {
+ grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
+ gpr_mu_init(&s->mu);
+ gpr_cv_init(&s->cv);
+ s->active_ports = 0;
+ s->destroyed_ports = 0;
+ s->shutdown = 0;
+ s->cb = NULL;
+ s->cb_arg = NULL;
+ s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
+ s->nports = 0;
+ s->port_capacity = INIT_PORT_CAP;
+
+ return s;
+}
+
+static void finish_shutdown(grpc_udp_server *s) {
+ s->shutdown_complete(s->shutdown_complete_arg);
+
+ gpr_mu_destroy(&s->mu);
+ gpr_cv_destroy(&s->cv);
+
+ gpr_free(s->ports);
+ gpr_free(s);
+}
+
+static void destroyed_port(void *server, int success) {
+ grpc_udp_server *s = server;
+ gpr_mu_lock(&s->mu);
+ s->destroyed_ports++;
+ if (s->destroyed_ports == s->nports) {
+ gpr_mu_unlock(&s->mu);
+ finish_shutdown(s);
+ } else {
+ gpr_mu_unlock(&s->mu);
+ }
+}
+
+static void dont_care_about_shutdown_completion(void *ignored) {}
+
+/* called when all listening endpoints have been shutdown, so no further
+ events will be received on them - at this point it's safe to destroy
+ things */
+static void deactivated_all_ports(grpc_udp_server *s) {
+ size_t i;
+
+ /* delete ALL the things */
+ gpr_mu_lock(&s->mu);
+
+ if (!s->shutdown) {
+ gpr_mu_unlock(&s->mu);
+ return;
+ }
+
+ if (s->nports) {
+ for (i = 0; i < s->nports; i++) {
+ server_port *sp = &s->ports[i];
+ if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(&sp->addr.un);
+ }
+ sp->destroyed_closure.cb = destroyed_port;
+ sp->destroyed_closure.cb_arg = s;
+ grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, "udp_listener_shutdown");
+ }
+ gpr_mu_unlock(&s->mu);
+ } else {
+ gpr_mu_unlock(&s->mu);
+ finish_shutdown(s);
+ }
+}
+
+void grpc_udp_server_destroy(
+ grpc_udp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg),
+ void *shutdown_complete_arg) {
+ size_t i;
+ gpr_mu_lock(&s->mu);
+
+ GPR_ASSERT(!s->shutdown);
+ s->shutdown = 1;
+
+ s->shutdown_complete = shutdown_complete
+ ? shutdown_complete
+ : dont_care_about_shutdown_completion;
+ s->shutdown_complete_arg = shutdown_complete_arg;
+
+ /* shutdown all fd's */
+ if (s->active_ports) {
+ for (i = 0; i < s->nports; i++) {
+ grpc_fd_shutdown(s->ports[i].emfd);
+ }
+ gpr_mu_unlock(&s->mu);
+ } else {
+ gpr_mu_unlock(&s->mu);
+ deactivated_all_ports(s);
+ }
+}
+
+/* Prepare a recently-created socket for listening. */
+static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) {
+ struct sockaddr_storage sockname_temp;
+ socklen_t sockname_len;
+ int get_local_ip;
+ int rc;
+
+ if (fd < 0) {
+ goto error;
+ }
+
+ get_local_ip = 1;
+ rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
+ sizeof(get_local_ip));
+ if (rc == 0 && addr->sa_family == AF_INET6) {
+ rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
+ sizeof(get_local_ip));
+ }
+
+ if (bind(fd, addr, addr_len) < 0) {
+ char *addr_str;
+ grpc_sockaddr_to_string(&addr_str, addr, 0);
+ gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
+ gpr_free(addr_str);
+ goto error;
+ }
+
+ sockname_len = sizeof(sockname_temp);
+ if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+ goto error;
+ }
+
+ return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+
+error:
+ if (fd >= 0) {
+ close(fd);
+ }
+ return -1;
+}
+
+/* event manager callback when reads are ready */
+static void on_read(void *arg, int success) {
+ server_port *sp = arg;
+
+ if (success == 0) {
+ gpr_mu_lock(&sp->server->mu);
+ if (0 == --sp->server->active_ports) {
+ gpr_mu_unlock(&sp->server->mu);
+ deactivated_all_ports(sp->server);
+ } else {
+ gpr_mu_unlock(&sp->server->mu);
+ }
+ return;
+ }
+
+ /* Tell the registered callback that data is available to read. */
+ GPR_ASSERT(sp->read_cb);
+ sp->read_cb(sp->fd, sp->server->cb, sp->server->cb_arg);
+
+ /* Re-arm the notification event so we get another chance to read. */
+ grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+}
+
+static int add_socket_to_server(grpc_udp_server *s, int fd,
+ const struct sockaddr *addr, int addr_len,
+ grpc_udp_server_read_cb read_cb) {
+ server_port *sp;
+ int port;
+ char *addr_str;
+ char *name;
+
+ port = prepare_socket(fd, addr, addr_len);
+ if (port >= 0) {
+ grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
+ gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
+ gpr_mu_lock(&s->mu);
+ GPR_ASSERT(!s->cb && "must add ports before starting server");
+ /* append it to the list under a lock */
+ if (s->nports == s->port_capacity) {
+ s->port_capacity *= 2;
+ s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
+ }
+ sp = &s->ports[s->nports++];
+ sp->server = s;
+ sp->fd = fd;
+ sp->emfd = grpc_fd_create(fd, name);
+ memcpy(sp->addr.untyped, addr, addr_len);
+ sp->addr_len = addr_len;
+ sp->read_cb = read_cb;
+ GPR_ASSERT(sp->emfd);
+ gpr_mu_unlock(&s->mu);
+ }
+
+ return port;
+}
+
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, int addr_len,
+ grpc_udp_server_read_cb read_cb) {
+ int allocated_port1 = -1;
+ int allocated_port2 = -1;
+ unsigned i;
+ int fd;
+ grpc_dualstack_mode dsmode;
+ struct sockaddr_in6 addr6_v4mapped;
+ struct sockaddr_in wild4;
+ struct sockaddr_in6 wild6;
+ struct sockaddr_in addr4_copy;
+ struct sockaddr *allocated_addr = NULL;
+ struct sockaddr_storage sockname_temp;
+ socklen_t sockname_len;
+ int port;
+
+ if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(addr);
+ }
+
+ /* Check if this is a wildcard port, and if so, try to keep the port the same
+ as some previously created listener. */
+ if (grpc_sockaddr_get_port(addr) == 0) {
+ for (i = 0; i < s->nports; i++) {
+ sockname_len = sizeof(sockname_temp);
+ if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
+ &sockname_len)) {
+ port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ if (port > 0) {
+ allocated_addr = malloc(addr_len);
+ memcpy(allocated_addr, addr, addr_len);
+ grpc_sockaddr_set_port(allocated_addr, port);
+ addr = allocated_addr;
+ break;
+ }
+ }
+ }
+ }
+
+ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+ addr = (const struct sockaddr *)&addr6_v4mapped;
+ addr_len = sizeof(addr6_v4mapped);
+ }
+
+ /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+ if (grpc_sockaddr_is_wildcard(addr, &port)) {
+ grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
+
+ /* Try listening on IPv6 first. */
+ addr = (struct sockaddr *)&wild6;
+ addr_len = sizeof(wild6);
+ fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+ allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+ if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
+ goto done;
+ }
+
+ /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+ if (port == 0 && allocated_port1 > 0) {
+ grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
+ }
+ addr = (struct sockaddr *)&wild4;
+ addr_len = sizeof(wild4);
+ }
+
+ fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+ if (fd < 0) {
+ gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+ }
+ if (dsmode == GRPC_DSMODE_IPV4 &&
+ grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
+ addr = (struct sockaddr *)&addr4_copy;
+ addr_len = sizeof(addr4_copy);
+ }
+ allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+
+done:
+ gpr_free(allocated_addr);
+ return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
+}
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index) {
+ return (index < s->nports) ? s->ports[index].fd : -1;
+}
+
+void grpc_udp_server_start(grpc_udp_server *s, grpc_pollset **pollsets,
+ size_t pollset_count,
+ grpc_udp_server_cb new_transport_cb, void *cb_arg) {
+ size_t i, j;
+ GPR_ASSERT(new_transport_cb);
+ gpr_mu_lock(&s->mu);
+ GPR_ASSERT(!s->cb);
+ GPR_ASSERT(s->active_ports == 0);
+ s->cb = new_transport_cb;
+ s->cb_arg = cb_arg;
+ s->pollsets = pollsets;
+ for (i = 0; i < s->nports; i++) {
+ for (j = 0; j < pollset_count; j++) {
+ grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd);
+ }
+ s->ports[i].read_closure.cb = on_read;
+ s->ports[i].read_closure.cb_arg = &s->ports[i];
+ grpc_fd_notify_on_read(s->ports[i].emfd, &s->ports[i].read_closure);
+ s->active_ports++;
+ }
+ gpr_mu_unlock(&s->mu);
+}
+
+/* TODO(rjshade): Add a test for this method. */
+void grpc_udp_server_write(server_port *sp, const char *buffer, size_t buf_len,
+ const struct sockaddr *peer_address) {
+ int rc;
+ rc = sendto(sp->fd, buffer, buf_len, 0, peer_address, sizeof(peer_address));
+ if (rc < 0) {
+ gpr_log(GPR_ERROR, "Unable to send data: %s", strerror(errno));
+ }
+}
+
+#endif
diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
new file mode 100644
index 0000000000..fcc4ba6e97
--- /dev/null
+++ b/src/core/iomgr/udp_server.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
+#define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
+
+#include "src/core/iomgr/endpoint.h"
+
+/* Forward decl of grpc_udp_server */
+typedef struct grpc_udp_server grpc_udp_server;
+
+/* New server callback: ep is the newly connected connection */
+typedef void (*grpc_udp_server_cb)(void *arg, grpc_endpoint *ep);
+
+/* Called when data is available to read from the socket. */
+typedef void (*grpc_udp_server_read_cb)(int fd,
+ grpc_udp_server_cb new_transport_cb,
+ void *cb_arg);
+
+/* Create a server, initially not bound to any ports */
+grpc_udp_server *grpc_udp_server_create(void);
+
+/* Start listening to bound ports */
+void grpc_udp_server_start(grpc_udp_server *server, grpc_pollset **pollsets,
+ size_t pollset_count, grpc_udp_server_cb cb,
+ void *cb_arg);
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index);
+
+/* Add a port to the server, returning port number on success, or negative
+ on failure.
+
+ The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
+ both IPv4 and IPv6 connections, but :: is the preferred style. This usually
+ creates one socket, but possibly two on systems which support IPv6,
+ but not dualstack sockets. */
+
+/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle
+ all of the multiple socket port matching logic in one place */
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, int addr_len,
+ grpc_udp_server_read_cb read_cb);
+
+void grpc_udp_server_destroy(grpc_udp_server *server,
+ void (*shutdown_done)(void *shutdown_done_arg),
+ void *shutdown_done_arg);
+
+/* Write the contents of buffer to the underlying UDP socket. */
+/*
+void grpc_udp_server_write(grpc_udp_server *s,
+ const char *buffer,
+ int buf_len,
+ const struct sockaddr* to);
+ */
+
+#endif /* GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H */
diff --git a/src/core/iomgr/wakeup_fd_eventfd.c b/src/core/iomgr/wakeup_fd_eventfd.c
index 52912235f8..08fdc74f17 100644
--- a/src/core/iomgr/wakeup_fd_eventfd.c
+++ b/src/core/iomgr/wakeup_fd_eventfd.c
@@ -75,8 +75,7 @@ static int eventfd_check_availability(void) {
}
const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
- eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy,
- eventfd_check_availability
-};
+ eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy,
+ eventfd_check_availability};
#endif /* GPR_LINUX_EVENTFD */
diff --git a/src/core/iomgr/wakeup_fd_nospecial.c b/src/core/iomgr/wakeup_fd_nospecial.c
index c1038bf379..78d763c103 100644
--- a/src/core/iomgr/wakeup_fd_nospecial.c
+++ b/src/core/iomgr/wakeup_fd_nospecial.c
@@ -43,12 +43,9 @@
#include "src/core/iomgr/wakeup_fd_posix.h"
#include <stddef.h>
-static int check_availability_invalid(void) {
- return 0;
-}
+static int check_availability_invalid(void) { return 0; }
const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
- NULL, NULL, NULL, NULL, check_availability_invalid
-};
+ NULL, NULL, NULL, NULL, check_availability_invalid};
-#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */
+#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c
index 9fc4ee2388..bd643e8061 100644
--- a/src/core/iomgr/wakeup_fd_pipe.c
+++ b/src/core/iomgr/wakeup_fd_pipe.c
@@ -94,4 +94,4 @@ const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = {
pipe_init, pipe_consume, pipe_wakeup, pipe_destroy,
pipe_check_availability};
-#endif /* GPR_POSIX_WAKUP_FD */
+#endif /* GPR_POSIX_WAKUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_pipe.h b/src/core/iomgr/wakeup_fd_pipe.h
index aa8f977ddb..01a13a97c0 100644
--- a/src/core/iomgr/wakeup_fd_pipe.h
+++ b/src/core/iomgr/wakeup_fd_pipe.h
@@ -38,4 +38,4 @@
extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */
diff --git a/src/core/iomgr/wakeup_fd_posix.c b/src/core/iomgr/wakeup_fd_posix.c
index e48f5223fa..d09fb78d12 100644
--- a/src/core/iomgr/wakeup_fd_posix.c
+++ b/src/core/iomgr/wakeup_fd_posix.c
@@ -53,9 +53,7 @@ void grpc_wakeup_fd_global_init_force_fallback(void) {
wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
}
-void grpc_wakeup_fd_global_destroy(void) {
- wakeup_fd_vtable = NULL;
-}
+void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; }
void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
wakeup_fd_vtable->init(fd_info);
@@ -73,4 +71,4 @@ void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) {
wakeup_fd_vtable->destroy(fd_info);
}
-#endif /* GPR_POSIX_WAKEUP_FD */
+#endif /* GPR_POSIX_WAKEUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h
index a4da4df51f..b6c086900d 100644
--- a/src/core/iomgr/wakeup_fd_posix.h
+++ b/src/core/iomgr/wakeup_fd_posix.h
@@ -96,4 +96,4 @@ void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info);
* wakeup_fd_nospecial.c if no such implementation exists. */
extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable;
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */
diff --git a/src/core/json/json.h b/src/core/json/json.h
index cac18ad885..573584bf6f 100644
--- a/src/core/json/json.h
+++ b/src/core/json/json.h
@@ -85,4 +85,4 @@ char* grpc_json_dump_to_string(grpc_json* json, int indent);
grpc_json* grpc_json_create(grpc_json_type type);
void grpc_json_destroy(grpc_json* json);
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */
+#endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */
diff --git a/src/core/json/json_common.h b/src/core/json/json_common.h
index 84bf375916..481695b38b 100644
--- a/src/core/json/json_common.h
+++ b/src/core/json/json_common.h
@@ -46,4 +46,4 @@ typedef enum {
GRPC_JSON_TOP_LEVEL
} grpc_json_type;
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */
+#endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
index c14094c290..c22d4edd47 100644
--- a/src/core/json/json_reader.c
+++ b/src/core/json/json_reader.c
@@ -42,27 +42,26 @@ static void json_reader_string_clear(grpc_json_reader* reader) {
}
static void json_reader_string_add_char(grpc_json_reader* reader,
- gpr_uint32 c) {
+ gpr_uint32 c) {
reader->vtable->string_add_char(reader->userdata, c);
}
static void json_reader_string_add_utf32(grpc_json_reader* reader,
- gpr_uint32 utf32) {
+ gpr_uint32 utf32) {
reader->vtable->string_add_utf32(reader->userdata, utf32);
}
-static gpr_uint32
- grpc_json_reader_read_char(grpc_json_reader* reader) {
+static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) {
return reader->vtable->read_char(reader->userdata);
}
static void json_reader_container_begins(grpc_json_reader* reader,
- grpc_json_type type) {
+ grpc_json_type type) {
reader->vtable->container_begins(reader->userdata, type);
}
-static grpc_json_type
- grpc_json_reader_container_ends(grpc_json_reader* reader) {
+static grpc_json_type grpc_json_reader_container_ends(
+ grpc_json_reader* reader) {
return reader->vtable->container_ends(reader->userdata);
}
@@ -101,8 +100,9 @@ void grpc_json_reader_init(grpc_json_reader* reader,
}
int grpc_json_reader_is_complete(grpc_json_reader* reader) {
- return ((reader->depth == 0) && ((reader->state == GRPC_JSON_STATE_END) ||
- (reader->state == GRPC_JSON_STATE_VALUE_END)));
+ return ((reader->depth == 0) &&
+ ((reader->state == GRPC_JSON_STATE_END) ||
+ (reader->state == GRPC_JSON_STATE_VALUE_END)));
}
grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
@@ -143,7 +143,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
case GRPC_JSON_STATE_VALUE_STRING:
if (c != ' ') return GRPC_JSON_PARSE_ERROR;
- if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate != 0)
+ return GRPC_JSON_PARSE_ERROR;
json_reader_string_add_char(reader, c);
break;
@@ -169,7 +170,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
switch (reader->state) {
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
case GRPC_JSON_STATE_VALUE_STRING:
- if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate != 0)
+ return GRPC_JSON_PARSE_ERROR;
json_reader_string_add_char(reader, c);
break;
@@ -253,7 +255,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
/* This is the \\ case. */
case GRPC_JSON_STATE_STRING_ESCAPE:
- if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate != 0)
+ return GRPC_JSON_PARSE_ERROR;
json_reader_string_add_char(reader, '\\');
if (reader->escaped_string_was_key) {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
@@ -276,7 +279,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
break;
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
- if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate != 0)
+ return GRPC_JSON_PARSE_ERROR;
if (c == '"') {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
json_reader_set_key(reader);
@@ -288,7 +292,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
break;
case GRPC_JSON_STATE_VALUE_STRING:
- if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate != 0)
+ return GRPC_JSON_PARSE_ERROR;
if (c == '"') {
reader->state = GRPC_JSON_STATE_VALUE_END;
json_reader_set_string(reader);
@@ -438,7 +443,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
if (reader->unicode_high_surrogate == 0)
return GRPC_JSON_PARSE_ERROR;
utf32 = 0x10000;
- utf32 += (gpr_uint32)((reader->unicode_high_surrogate - 0xd800) * 0x400);
+ utf32 += (gpr_uint32)(
+ (reader->unicode_high_surrogate - 0xd800) * 0x400);
utf32 += (gpr_uint32)(reader->unicode_char - 0xdc00);
json_reader_string_add_utf32(reader, utf32);
reader->unicode_high_surrogate = 0;
diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h
index b1a5ace8fb..4d5487f790 100644
--- a/src/core/json/json_reader.h
+++ b/src/core/json/json_reader.h
@@ -157,4 +157,4 @@ void grpc_json_reader_init(grpc_json_reader* reader,
*/
int grpc_json_reader_is_complete(grpc_json_reader* reader);
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */
+#endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
index 03c1099167..e6622ec461 100644
--- a/src/core/json/json_string.c
+++ b/src/core/json/json_string.c
@@ -73,7 +73,6 @@ typedef struct {
size_t allocated;
} json_writer_userdata;
-
/* This function checks if there's enough space left in the output buffer,
* and will enlarge it if necessary. We're only allocating chunks of 256
* bytes at a time (or multiples thereof).
@@ -97,8 +96,8 @@ static void json_writer_output_char(void* userdata, char c) {
state->free_space--;
}
-static void json_writer_output_string_with_len(void* userdata,
- const char* str, size_t len) {
+static void json_writer_output_string_with_len(void* userdata, const char* str,
+ size_t len) {
json_writer_userdata* state = userdata;
json_writer_output_check(userdata, len);
memcpy(state->output + state->string_len, str, len);
@@ -106,8 +105,7 @@ static void json_writer_output_string_with_len(void* userdata,
state->free_space -= len;
}
-static void json_writer_output_string(void* userdata,
- const char* str) {
+static void json_writer_output_string(void* userdata, const char* str) {
size_t len = strlen(str);
json_writer_output_string_with_len(userdata, str, len);
}
@@ -184,8 +182,7 @@ static gpr_uint32 json_reader_read_char(void* userdata) {
/* Helper function to create a new grpc_json object and link it into
* our tree-in-progress inside our opaque structure.
*/
-static grpc_json* json_create_and_link(void* userdata,
- grpc_json_type type) {
+static grpc_json* json_create_and_link(void* userdata, grpc_json_type type) {
json_reader_userdata* state = userdata;
grpc_json* json = grpc_json_create(type);
@@ -201,7 +198,7 @@ static grpc_json* json_create_and_link(void* userdata,
json->parent->child = json;
}
if (json->parent->type == GRPC_JSON_OBJECT) {
- json->key = (char*) state->key;
+ json->key = (char*)state->key;
}
}
if (!state->top) {
@@ -261,13 +258,13 @@ static void json_reader_set_key(void* userdata) {
static void json_reader_set_string(void* userdata) {
json_reader_userdata* state = userdata;
grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING);
- json->value = (char*) state->string;
+ json->value = (char*)state->string;
}
static int json_reader_set_number(void* userdata) {
json_reader_userdata* state = userdata;
grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
- json->value = (char*) state->string;
+ json->value = (char*)state->string;
return 1;
}
@@ -287,32 +284,25 @@ static void json_reader_set_null(void* userdata) {
}
static grpc_json_reader_vtable reader_vtable = {
- json_reader_string_clear,
- json_reader_string_add_char,
- json_reader_string_add_utf32,
- json_reader_read_char,
- json_reader_container_begins,
- json_reader_container_ends,
- json_reader_set_key,
- json_reader_set_string,
- json_reader_set_number,
- json_reader_set_true,
- json_reader_set_false,
- json_reader_set_null
-};
+ json_reader_string_clear, json_reader_string_add_char,
+ json_reader_string_add_utf32, json_reader_read_char,
+ json_reader_container_begins, json_reader_container_ends,
+ json_reader_set_key, json_reader_set_string,
+ json_reader_set_number, json_reader_set_true,
+ json_reader_set_false, json_reader_set_null};
/* And finally, let's define our public API. */
grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
grpc_json_reader reader;
json_reader_userdata state;
- grpc_json *json = NULL;
+ grpc_json* json = NULL;
grpc_json_reader_status status;
if (!input) return NULL;
state.top = state.current_container = state.current_value = NULL;
state.string = state.key = NULL;
- state.string_ptr = state.input = (gpr_uint8*) input;
+ state.string_ptr = state.input = (gpr_uint8*)input;
state.remaining_input = size;
grpc_json_reader_init(&reader, &reader_vtable, &state);
@@ -333,8 +323,8 @@ grpc_json* grpc_json_parse_string(char* input) {
return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
}
-static void json_dump_recursive(grpc_json_writer* writer,
- grpc_json* json, int in_object) {
+static void json_dump_recursive(grpc_json_writer* writer, grpc_json* json,
+ int in_object) {
while (json) {
if (in_object) grpc_json_writer_object_key(writer, json->key);
@@ -370,10 +360,8 @@ static void json_dump_recursive(grpc_json_writer* writer,
}
static grpc_json_writer_vtable writer_vtable = {
- json_writer_output_char,
- json_writer_output_string,
- json_writer_output_string_with_len
-};
+ json_writer_output_char, json_writer_output_string,
+ json_writer_output_string_with_len};
char* grpc_json_dump_to_string(grpc_json* json, int indent) {
grpc_json_writer writer;
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
index bed9a9bfa5..ca9c835825 100644
--- a/src/core/json/json_writer.c
+++ b/src/core/json/json_writer.c
@@ -41,11 +41,13 @@ static void json_writer_output_char(grpc_json_writer* writer, char c) {
writer->vtable->output_char(writer->userdata, c);
}
-static void json_writer_output_string(grpc_json_writer* writer, const char* str) {
+static void json_writer_output_string(grpc_json_writer* writer,
+ const char* str) {
writer->vtable->output_string(writer->userdata, str);
}
-static void json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) {
+static void json_writer_output_string_with_len(grpc_json_writer* writer,
+ const char* str, size_t len) {
writer->vtable->output_string_with_len(writer->userdata, str, len);
}
@@ -58,8 +60,7 @@ void grpc_json_writer_init(grpc_json_writer* writer, int indent,
writer->userdata = userdata;
}
-static void json_writer_output_indent(
- grpc_json_writer* writer) {
+static void json_writer_output_indent(grpc_json_writer* writer) {
static const char spacesstr[] =
" "
" "
@@ -99,14 +100,15 @@ static void json_writer_value_end(grpc_json_writer* writer) {
}
}
-static void json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) {
+static void json_writer_escape_utf16(grpc_json_writer* writer,
+ gpr_uint16 utf16) {
static const char hex[] = "0123456789abcdef";
json_writer_output_string_with_len(writer, "\\u", 2);
json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
- json_writer_output_char(writer, hex[(utf16) & 0x0f]);
+ json_writer_output_char(writer, hex[(utf16)&0x0f]);
}
static void json_writer_escape_string(grpc_json_writer* writer,
@@ -173,8 +175,8 @@ static void json_writer_escape_string(grpc_json_writer* writer,
* Any other range is technically reserved for future usage, so if we
* don't want the software to break in the future, we have to allow
* anything else. The first non-unicode character is 0x110000. */
- if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) ||
- (utf32 >= 0x110000)) break;
+ if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
+ break;
if (utf32 >= 0x10000) {
/* If utf32 contains a character that is above 0xffff, it needs to be
* broken down into a utf-16 surrogate pair. A surrogate pair is first
@@ -194,7 +196,8 @@ static void json_writer_escape_string(grpc_json_writer* writer,
*/
utf32 -= 0x10000;
json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10)));
- json_writer_escape_utf16(writer, (gpr_uint16)(0xdc00 | (utf32 & 0x3ff)));
+ json_writer_escape_utf16(writer,
+ (gpr_uint16)(0xdc00 | (utf32 & 0x3ff)));
} else {
json_writer_escape_utf16(writer, (gpr_uint16)utf32);
}
@@ -204,7 +207,8 @@ static void json_writer_escape_string(grpc_json_writer* writer,
json_writer_output_char(writer, '"');
}
-void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type) {
+void grpc_json_writer_container_begins(grpc_json_writer* writer,
+ grpc_json_type type) {
if (!writer->got_key) json_writer_value_end(writer);
json_writer_output_indent(writer);
json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
@@ -213,7 +217,8 @@ void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type
writer->depth++;
}
-void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type) {
+void grpc_json_writer_container_ends(grpc_json_writer* writer,
+ grpc_json_type type) {
if (writer->indent && !writer->container_empty)
json_writer_output_char(writer, '\n');
writer->depth--;
@@ -238,14 +243,16 @@ void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) {
writer->got_key = 0;
}
-void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len) {
+void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer,
+ const char* string, size_t len) {
if (!writer->got_key) json_writer_value_end(writer);
json_writer_output_indent(writer);
json_writer_output_string_with_len(writer, string, len);
writer->got_key = 0;
}
-void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string) {
+void grpc_json_writer_value_string(grpc_json_writer* writer,
+ const char* string) {
if (!writer->got_key) json_writer_value_end(writer);
json_writer_output_indent(writer);
json_writer_escape_string(writer, string);
diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h
index dfa61a5fef..a299dfabf8 100644
--- a/src/core/json/json_writer.h
+++ b/src/core/json/json_writer.h
@@ -78,16 +78,20 @@ void grpc_json_writer_init(grpc_json_writer* writer, int indent,
grpc_json_writer_vtable* vtable, void* userdata);
/* Signals the beginning of a container. */
-void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type);
+void grpc_json_writer_container_begins(grpc_json_writer* writer,
+ grpc_json_type type);
/* Signals the end of a container. */
-void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type);
+void grpc_json_writer_container_ends(grpc_json_writer* writer,
+ grpc_json_type type);
/* Writes down an object key for the next value. */
void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string);
/* Sets a raw value. Useful for numbers. */
void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string);
/* Sets a raw value with its length. Useful for values like true or false. */
-void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len);
+void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer,
+ const char* string, size_t len);
/* Sets a string value. It'll be escaped, and utf-8 validated. */
-void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string);
+void grpc_json_writer_value_string(grpc_json_writer* writer,
+ const char* string);
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */
+#endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
index 036d02f187..92dbab9042 100644
--- a/src/core/profiling/timers.h
+++ b/src/core/profiling/timers.h
@@ -88,7 +88,7 @@ enum grpc_profiling_tags {
} while (0)
#define GRPC_TIMER_IMPORTANT_MARK(tag, id) \
- do { \
+ do { \
} while (0)
#define GRPC_TIMER_BEGIN(tag, id) \
diff --git a/src/core/security/auth_filters.h b/src/core/security/auth_filters.h
index ff921690e0..c179b54bec 100644
--- a/src/core/security/auth_filters.h
+++ b/src/core/security/auth_filters.h
@@ -39,4 +39,4 @@
extern const grpc_channel_filter grpc_client_auth_filter;
extern const grpc_channel_filter grpc_server_auth_filter;
-#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */
+#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */
diff --git a/src/core/security/base64.h b/src/core/security/base64.h
index b9abc07b52..31ae982691 100644
--- a/src/core/security/base64.h
+++ b/src/core/security/base64.h
@@ -49,4 +49,4 @@ gpr_slice grpc_base64_decode(const char *b64, int url_safe);
gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
int url_safe);
-#endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */
+#endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 410852da52..8e63978b82 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -200,7 +200,7 @@ static void auth_start_transport_op(grpc_call_element *elem,
channel_data *chand = elem->channel_data;
grpc_linked_mdelem *l;
size_t i;
- grpc_client_security_context* sec_ctx = NULL;
+ grpc_client_security_context *sec_ctx = NULL;
if (calld->security_context_set == 0) {
calld->security_context_set = 1;
@@ -316,9 +316,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
(grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
sc, "client_auth_filter");
chand->md_ctx = metadata_context;
- chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0);
+ chand->authority_string =
+ grpc_mdstr_from_string(chand->md_ctx, ":authority", 0);
chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0);
- chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0);
+ chand->error_msg_key =
+ grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0);
chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0);
}
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 6421ce673d..8852cab3e7 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -793,16 +793,16 @@ void on_simulated_token_fetch_done(void *user_data, int success) {
(grpc_credentials_metadata_request *)user_data;
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
GPR_ASSERT(success);
- r->cb(r->user_data, c->md_store->entries,
- c->md_store->num_entries, GRPC_CREDENTIALS_OK);
+ r->cb(r->user_data, c->md_store->entries, c->md_store->num_entries,
+ GRPC_CREDENTIALS_OK);
grpc_credentials_metadata_request_destroy(r);
}
static void md_only_test_get_request_metadata(grpc_credentials *creds,
- grpc_pollset *pollset,
- const char *service_url,
- grpc_credentials_metadata_cb cb,
- void *user_data) {
+ grpc_pollset *pollset,
+ const char *service_url,
+ grpc_credentials_metadata_cb cb,
+ void *user_data) {
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) {
@@ -854,10 +854,10 @@ static int access_token_has_request_metadata_only(
}
static void access_token_get_request_metadata(grpc_credentials *creds,
- grpc_pollset *pollset,
- const char *service_url,
- grpc_credentials_metadata_cb cb,
- void *user_data) {
+ grpc_pollset *pollset,
+ const char *service_url,
+ grpc_credentials_metadata_cb cb,
+ void *user_data) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
}
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 04736525dc..29cd1ac87f 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -192,8 +192,9 @@ void grpc_flush_cached_google_default_credentials(void);
/* Metadata-only credentials with the specified key and value where
asynchronicity can be simulated for testing. */
-grpc_credentials *grpc_md_only_test_credentials_create(
- const char *md_key, const char *md_value, int is_async);
+grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
+ const char *md_value,
+ int is_async);
/* Private constructor for jwt credentials from an already parsed json key.
Takes ownership of the key. */
diff --git a/src/core/security/credentials_metadata.c b/src/core/security/credentials_metadata.c
index 22c786be56..b8a132f1ea 100644
--- a/src/core/security/credentials_metadata.c
+++ b/src/core/security/credentials_metadata.c
@@ -47,7 +47,8 @@ static void store_ensure_capacity(grpc_credentials_md_store *store) {
grpc_credentials_md_store *grpc_credentials_md_store_create(
size_t initial_capacity) {
- grpc_credentials_md_store *store = gpr_malloc(sizeof(grpc_credentials_md_store));
+ grpc_credentials_md_store *store =
+ gpr_malloc(sizeof(grpc_credentials_md_store));
memset(store, 0, sizeof(grpc_credentials_md_store));
if (initial_capacity > 0) {
store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md));
@@ -98,4 +99,3 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) {
gpr_free(store);
}
}
-
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index d1f228665f..d6092ece32 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -203,8 +203,8 @@ end:
/* Blend with default ssl credentials and add a global reference so that it
can be cached and re-served. */
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
- default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
- ssl_creds, result));
+ default_credentials = grpc_credentials_ref(
+ grpc_composite_credentials_create(ssl_creds, result));
GPR_ASSERT(default_credentials != NULL);
grpc_credentials_unref(ssl_creds);
grpc_credentials_unref(result);
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
index 091dfefb6e..7e06864ff3 100644
--- a/src/core/security/json_token.h
+++ b/src/core/security/json_token.h
@@ -115,4 +115,4 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
/* Destructs the object. */
void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
-#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */
+#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */
diff --git a/src/core/security/jwt_verifier.h b/src/core/security/jwt_verifier.h
index 8077e24883..7a32debfcb 100644
--- a/src/core/security/jwt_verifier.h
+++ b/src/core/security/jwt_verifier.h
@@ -133,4 +133,3 @@ grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
const char *audience);
#endif /* GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H */
-
diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c
index 95fbf71f3d..81b3e33cb2 100644
--- a/src/core/security/secure_endpoint.c
+++ b/src/core/security/secure_endpoint.c
@@ -332,7 +332,7 @@ static void endpoint_add_to_pollset(grpc_endpoint *secure_ep,
}
static void endpoint_add_to_pollset_set(grpc_endpoint *secure_ep,
- grpc_pollset_set *pollset_set) {
+ grpc_pollset_set *pollset_set) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set);
}
diff --git a/src/core/security/secure_endpoint.h b/src/core/security/secure_endpoint.h
index 93c29b5111..c563bdd9c5 100644
--- a/src/core/security/secure_endpoint.h
+++ b/src/core/security/secure_endpoint.h
@@ -46,4 +46,4 @@ grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
gpr_slice *leftover_slices, size_t leftover_nslices);
-#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */
+#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
index 29025f5236..d9b802556d 100644
--- a/src/core/security/secure_transport_setup.h
+++ b/src/core/security/secure_transport_setup.h
@@ -50,4 +50,4 @@ void grpc_setup_secure_transport(grpc_security_connector *connector,
grpc_secure_transport_setup_done_cb cb,
void *user_data);
-#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */
+#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 1ef0fc9255..c1b434f302 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -204,8 +204,7 @@ int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
return 1;
}
-int grpc_auth_context_peer_is_authenticated(
- const grpc_auth_context *ctx) {
+int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) {
return ctx->peer_identity_property_name == NULL ? 0 : 1;
}
@@ -326,4 +325,3 @@ grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
}
return NULL;
}
-
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 7fcd438cf6..a9a0306410 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -112,5 +112,4 @@ grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg(
grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
const grpc_channel_args *args);
-#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
-
+#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index 2fc689caec..2f42f01f53 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -212,8 +212,7 @@ static void init_call_elem(grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_call_element *elem) {
-}
+static void destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h
index eb4349c311..ac1ff24866 100644
--- a/src/core/statistics/census_interface.h
+++ b/src/core/statistics/census_interface.h
@@ -73,4 +73,4 @@ census_op_id census_tracing_start_op(void);
/* Ends tracing. Calling this function will invalidate the input op_id. */
void census_tracing_end_op(census_op_id op_id);
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */
diff --git a/src/core/statistics/census_log.h b/src/core/statistics/census_log.h
index 06869b7a33..60b6d597df 100644
--- a/src/core/statistics/census_log.h
+++ b/src/core/statistics/census_log.h
@@ -88,4 +88,4 @@ size_t census_log_remaining_space(void);
out-of-space. */
int census_log_out_of_space_count(void);
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */
diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c
index 3e571b1143..b836987cf0 100644
--- a/src/core/statistics/census_rpc_stats.c
+++ b/src/core/statistics/census_rpc_stats.c
@@ -85,8 +85,8 @@ static void delete_key(void* key) { gpr_free(key); }
static const census_ht_option ht_opt = {
CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */,
- simple_hash /* hash function */, cmp_str_keys /* key comparator */,
- delete_stats /* data deleter */, delete_key /* key deleter */
+ simple_hash /* hash function */, cmp_str_keys /* key comparator */,
+ delete_stats /* data deleter */, delete_key /* key deleter */
};
static void init_rpc_stats(void* stats) {
diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h
index 9336dce1f8..aec31c1971 100644
--- a/src/core/statistics/census_rpc_stats.h
+++ b/src/core/statistics/census_rpc_stats.h
@@ -98,4 +98,4 @@ void census_stats_store_shutdown(void);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
index 3036ba5407..f2a09dc06e 100644
--- a/src/core/statistics/census_tracing.c
+++ b/src/core/statistics/census_tracing.c
@@ -60,8 +60,11 @@ static void delete_trace_obj(void* obj) {
}
static const census_ht_option ht_opt = {
- CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */,
- NULL /* compare_keys */, delete_trace_obj /* delete data */,
+ CENSUS_HT_UINT64 /* key type*/,
+ 571 /* n_of_buckets */,
+ NULL /* hash */,
+ NULL /* compare_keys */,
+ delete_trace_obj /* delete data */,
NULL /* delete key */
};
diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h
index a4494b510c..08305c2469 100644
--- a/src/core/statistics/census_tracing.h
+++ b/src/core/statistics/census_tracing.h
@@ -93,4 +93,4 @@ census_trace_obj** census_get_active_ops(int* num_active_ops);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */
diff --git a/src/core/statistics/hash_table.h b/src/core/statistics/hash_table.h
index 7bcb4bcd9b..b7f8e11af4 100644
--- a/src/core/statistics/hash_table.h
+++ b/src/core/statistics/hash_table.h
@@ -128,4 +128,4 @@ typedef void (*census_ht_itr_cb)(census_ht_key key, const void* val_ptr,
should not invalidate data entries. */
gpr_uint64 census_ht_for_all(const census_ht* ht, census_ht_itr_cb);
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */
diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c
deleted file mode 100644
index 4756f1e125..0000000000
--- a/src/core/support/cancellable.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Implementation for gpr_cancellable */
-
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-void gpr_cancellable_init(gpr_cancellable *c) {
- gpr_mu_init(&c->mu);
- c->cancelled = 0;
- c->waiters.next = &c->waiters;
- c->waiters.prev = &c->waiters;
- c->waiters.mu = NULL;
- c->waiters.cv = NULL;
-}
-
-void gpr_cancellable_destroy(gpr_cancellable *c) { gpr_mu_destroy(&c->mu); }
-
-int gpr_cancellable_is_cancelled(gpr_cancellable *c) {
- return gpr_atm_acq_load(&c->cancelled) != 0;
-}
-
-/* Threads in gpr_cv_cancellable_wait(cv, mu, ..., c) place themselves on a
- linked list c->waiters of gpr_cancellable_list_ before waiting on their
- condition variables. They check for cancellation while holding *mu. Thus,
- to wake a thread from gpr_cv_cancellable_wait(), it suffices to:
- - set c->cancelled
- - acquire and release *mu
- - gpr_cv_broadcast(cv)
-
- However, gpr_cancellable_cancel() may not use gpr_mu_lock(mu), since the
- caller may already hold *mu---a possible deadlock. (If we knew the caller
- did not hold *mu, care would still be needed, because c->mu follows *mu in
- the locking order, so *mu could not be acquired while holding c->mu---which
- is needed to iterate over c->waiters.)
-
- Therefore, gpr_cancellable_cancel() uses gpr_mu_trylock() rather than
- gpr_mu_lock(), and retries until either gpr_mu_trylock() succeeds or the
- thread leaves gpr_cv_cancellable_wait() for other reasons. In the first
- case, gpr_cancellable_cancel() removes the entry from the waiters list; in
- the second, the waiting thread removes itself from the list.
-
- A one-entry cache of mutexes and condition variables processed is kept to
- avoid doing the same work again and again if many threads are blocked in the
- same place. However, it's important to broadcast on a condition variable if
- the corresponding mutex has been locked successfully, even if the condition
- variable has been signalled before. */
-
-void gpr_cancellable_cancel(gpr_cancellable *c) {
- if (!gpr_cancellable_is_cancelled(c)) {
- int failures;
- int backoff = 1;
- do {
- struct gpr_cancellable_list_ *l;
- struct gpr_cancellable_list_ *nl;
- gpr_mu *omu = 0; /* one-element cache of a processed gpr_mu */
- gpr_cv *ocv = 0; /* one-element cache of a processd gpr_cv */
- gpr_mu_lock(&c->mu);
- gpr_atm_rel_store(&c->cancelled, 1);
- failures = 0;
- for (l = c->waiters.next; l != &c->waiters; l = nl) {
- nl = l->next;
- if (omu != l->mu) {
- omu = l->mu;
- if (gpr_mu_trylock(l->mu)) {
- gpr_mu_unlock(l->mu);
- l->next->prev = l->prev; /* remove *l from list */
- l->prev->next = l->next;
- /* allow unconditional dequeue in gpr_cv_cancellable_wait() */
- l->next = l;
- l->prev = l;
- ocv = 0; /* force broadcast */
- } else {
- failures++;
- }
- }
- if (ocv != l->cv) {
- ocv = l->cv;
- gpr_cv_broadcast(l->cv);
- }
- }
- gpr_mu_unlock(&c->mu);
- if (failures != 0) {
- if (backoff < 10) {
- volatile int i;
- for (i = 0; i != (1 << backoff); i++) {
- }
- backoff++;
- } else {
- gpr_event ev;
- gpr_event_init(&ev);
- gpr_event_wait(
- &ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_micros(1000, GPR_TIMESPAN)));
- }
- }
- } while (failures != 0);
- }
-}
-
-int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
- gpr_cancellable *c) {
- gpr_int32 timeout;
- gpr_mu_lock(&c->mu);
- timeout = gpr_cancellable_is_cancelled(c);
- if (!timeout) {
- struct gpr_cancellable_list_ le;
- le.mu = mu;
- le.cv = cv;
- le.next = c->waiters.next;
- le.prev = &c->waiters;
- le.next->prev = &le;
- le.prev->next = &le;
- gpr_mu_unlock(&c->mu);
- timeout = gpr_cv_wait(cv, mu, abs_deadline);
- gpr_mu_lock(&c->mu);
- le.next->prev = le.prev;
- le.prev->next = le.next;
- if (!timeout) {
- timeout = gpr_cancellable_is_cancelled(c);
- }
- }
- gpr_mu_unlock(&c->mu);
- return timeout;
-}
diff --git a/src/core/support/cpu_iphone.c b/src/core/support/cpu_iphone.c
index d412a6d7ee..82b49b47bc 100644
--- a/src/core/support/cpu_iphone.c
+++ b/src/core/support/cpu_iphone.c
@@ -36,9 +36,7 @@
#ifdef GPR_CPU_IPHONE
/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */
-unsigned gpr_cpu_num_cores(void) {
- return 1;
-}
+unsigned gpr_cpu_num_cores(void) { return 1; }
/* Most code that's using this is using it to shard across work queues. So
unless profiling shows it's a problem or there appears a way to detect the
@@ -46,8 +44,6 @@ unsigned gpr_cpu_num_cores(void) {
Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing
it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range,
and some code might be relying on it. */
-unsigned gpr_cpu_current_cpu(void) {
- return 0;
-}
+unsigned gpr_cpu_current_cpu(void) { return 0; }
#endif /* GPR_CPU_IPHONE */
diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c
index 282d4daab1..7af6a8f009 100644
--- a/src/core/support/cpu_linux.c
+++ b/src/core/support/cpu_linux.c
@@ -33,7 +33,7 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
-#endif /* _GNU_SOURCE */
+#endif /* _GNU_SOURCE */
#include <grpc/support/port_platform.h>
diff --git a/src/core/support/env.h b/src/core/support/env.h
index 4f2e394d14..24172d8673 100644
--- a/src/core/support/env.h
+++ b/src/core/support/env.h
@@ -57,4 +57,4 @@ void gpr_setenv(const char *name, const char *value);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */
diff --git a/src/core/support/file.h b/src/core/support/file.h
index 1dafe390e3..d8b7cea44f 100644
--- a/src/core/support/file.h
+++ b/src/core/support/file.h
@@ -60,4 +60,4 @@ FILE *gpr_tmpfile(const char *prefix, char **tmp_filename);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_FILE_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_FILE_H */
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
index 9029703891..78dbf98684 100644
--- a/src/core/support/histogram.c
+++ b/src/core/support/histogram.c
@@ -191,15 +191,18 @@ static double threshold_for_count_below(gpr_histogram *h, double count_below) {
break;
}
}
- return (bucket_start(h, (double)lower_idx) + bucket_start(h, (double)upper_idx)) / 2.0;
+ return (bucket_start(h, (double)lower_idx) +
+ bucket_start(h, (double)upper_idx)) /
+ 2.0;
} else {
/* treat values as uniform throughout the bucket, and find where this value
should lie */
lower_bound = bucket_start(h, (double)lower_idx);
upper_bound = bucket_start(h, (double)(lower_idx + 1));
- return GPR_CLAMP(upper_bound - (upper_bound - lower_bound) *
- (count_so_far - count_below) /
- h->buckets[lower_idx],
+ return GPR_CLAMP(upper_bound -
+ (upper_bound - lower_bound) *
+ (count_so_far - count_below) /
+ h->buckets[lower_idx],
h->min_seen, h->max_seen);
}
}
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 5ac36e7b95..02f64d8b7e 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -93,8 +93,8 @@ void gpr_default_log(gpr_log_func_args *args) {
}
gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
- gpr_log_severity_string(args->severity), time_buffer,
- (int)(now.tv_nsec), gettid(), display_file, args->line);
+ gpr_log_severity_string(args->severity), time_buffer,
+ (int)(now.tv_nsec), gettid(), display_file, args->line);
fprintf(stderr, "%-60s %s\n", prefix, args->message);
gpr_free(prefix);
diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h
index 85ab2fe4bf..343fcb99f7 100644
--- a/src/core/support/murmur_hash.h
+++ b/src/core/support/murmur_hash.h
@@ -41,4 +41,4 @@
/* compute the hash of key (length len) */
gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed);
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
index e4196a48c6..53024e88f1 100644
--- a/src/core/support/slice.c
+++ b/src/core/support/slice.c
@@ -284,7 +284,8 @@ gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
head.refcount = NULL;
head.data.inlined.length = (gpr_uint8)split;
memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
- source->data.inlined.length = (gpr_uint8)(source->data.inlined.length - split);
+ source->data.inlined.length =
+ (gpr_uint8)(source->data.inlined.length - split);
memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
source->data.inlined.length);
} else if (split < sizeof(head.data.inlined.bytes)) {
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index 6e6c72a2bf..987d5cb9b5 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -116,7 +116,8 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
GPR_SLICE_INLINED_SIZE) {
memcpy(back->data.inlined.bytes + back->data.inlined.length,
s.data.inlined.bytes, s.data.inlined.length);
- back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + s.data.inlined.length);
+ back->data.inlined.length =
+ (gpr_uint8)(back->data.inlined.length + s.data.inlined.length);
} else {
size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
memcpy(back->data.inlined.bytes + back->data.inlined.length,
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index bc741f8c70..27ecf62280 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -67,7 +67,7 @@ typedef union lockfree_node {
#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */
#define INVALID_ENTRY_INDEX \
((1 << 16) - 1) /* reserve this entry as invalid \
- */
+ */
struct gpr_stack_lockfree {
lockfree_node *entries;
@@ -75,7 +75,7 @@ struct gpr_stack_lockfree {
#ifndef NDEBUG
/* Bitmap of pushed entries to check for double-push or pop */
- gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))];
+ gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))];
#endif
};
@@ -123,13 +123,13 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
#ifndef NDEBUG
/* Check for double push */
{
- int pushed_index = entry / (8*sizeof(gpr_atm));
- int pushed_bit = entry % (8*sizeof(gpr_atm));
+ int pushed_index = entry / (8 * sizeof(gpr_atm));
+ int pushed_bit = entry % (8 * sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
- (gpr_atm)(1UL << pushed_bit));
- GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0);
+ (gpr_atm)(1UL << pushed_bit));
+ GPR_ASSERT((old_val & (1UL << pushed_bit)) == 0);
}
#endif
@@ -161,13 +161,13 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
#ifndef NDEBUG
/* Check for valid pop */
{
- int pushed_index = head.contents.index / (8*sizeof(gpr_atm));
- int pushed_bit = head.contents.index % (8*sizeof(gpr_atm));
+ int pushed_index = head.contents.index / (8 * sizeof(gpr_atm));
+ int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
- -(gpr_atm)(1UL << pushed_bit));
- GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0);
+ -(gpr_atm)(1UL << pushed_bit));
+ GPR_ASSERT((old_val & (1UL << pushed_bit)) != 0);
}
#endif
diff --git a/src/core/support/string.c b/src/core/support/string.c
index 9babbd910a..af0389ea83 100644
--- a/src/core/support/string.c
+++ b/src/core/support/string.c
@@ -125,7 +125,6 @@ char *gpr_dump_slice(gpr_slice s, gpr_uint32 flags) {
flags);
}
-
int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) {
gpr_uint32 out = 0;
gpr_uint32 new;
@@ -187,9 +186,9 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
for (i = 0; i < nstrs; i++) {
out_length += strlen(strs[i]);
}
- out_length += 1; /* null terminator */
+ out_length += 1; /* null terminator */
if (nstrs > 0) {
- out_length += sep_len * (nstrs - 1); /* separators */
+ out_length += sep_len * (nstrs - 1); /* separators */
}
out = gpr_malloc(out_length);
out_length = 0;
@@ -214,10 +213,8 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
* str.
*
* Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
-static int slice_find_separator_offset(const gpr_slice str,
- const char *sep,
- const size_t read_offset,
- size_t *begin,
+static int slice_find_separator_offset(const gpr_slice str, const char *sep,
+ const size_t read_offset, size_t *begin,
size_t *end) {
size_t i;
const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset;
@@ -255,9 +252,7 @@ void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) {
}
}
-void gpr_strvec_init(gpr_strvec *sv) {
- memset(sv, 0, sizeof(*sv));
-}
+void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); }
void gpr_strvec_destroy(gpr_strvec *sv) {
size_t i;
@@ -270,11 +265,11 @@ void gpr_strvec_destroy(gpr_strvec *sv) {
void gpr_strvec_add(gpr_strvec *sv, char *str) {
if (sv->count == sv->capacity) {
sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2);
- sv->strs = gpr_realloc(sv->strs, sizeof(char*) * sv->capacity);
+ sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity);
}
sv->strs[sv->count++] = str;
}
char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) {
- return gpr_strjoin((const char**)sv->strs, sv->count, final_length);
+ return gpr_strjoin((const char **)sv->strs, sv->count, final_length);
}
diff --git a/src/core/support/string.h b/src/core/support/string.h
index 3ac4abeef8..a28e00fd3e 100644
--- a/src/core/support/string.h
+++ b/src/core/support/string.h
@@ -47,7 +47,7 @@ extern "C" {
/* String utility functions */
/* Flags for gpr_dump function. */
-#define GPR_DUMP_HEX 0x00000001
+#define GPR_DUMP_HEX 0x00000001
#define GPR_DUMP_ASCII 0x00000002
/* Converts array buf, of length len, into a C string according to the flags.
@@ -108,4 +108,4 @@ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
index 27b9f3637a..8ffb0a225e 100644
--- a/src/core/support/string_win32.c
+++ b/src/core/support/string_win32.c
@@ -99,13 +99,9 @@ LPSTR gpr_tchar_to_char(LPCTSTR input) {
return ret;
}
#else
-char *gpr_tchar_to_char(LPTSTR input) {
- return gpr_strdup(input);
-}
+char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); }
-char *gpr_char_to_tchar(LPTSTR input) {
- return gpr_strdup(input);
-}
+char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); }
#endif
#endif /* GPR_WIN32 */
diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h
index 1260aa55c1..e3043656fb 100644
--- a/src/core/support/string_win32.h
+++ b/src/core/support/string_win32.h
@@ -42,6 +42,6 @@
LPTSTR gpr_char_to_tchar(LPCSTR input);
LPSTR gpr_tchar_to_char(LPCTSTR input);
-#endif /* GPR_WIN32 */
+#endif /* GPR_WIN32 */
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */
diff --git a/src/core/support/sync.c b/src/core/support/sync.c
index 856b5adb86..d3cf77faea 100644
--- a/src/core/support/sync.c
+++ b/src/core/support/sync.c
@@ -94,21 +94,6 @@ void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) {
return result;
}
-void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
- gpr_cancellable *c) {
- void *result = (void *)gpr_atm_acq_load(&ev->state);
- if (result == NULL) {
- struct sync_array_s *s = hash(ev);
- gpr_mu_lock(&s->mu);
- do {
- result = (void *)gpr_atm_acq_load(&ev->state);
- } while (result == NULL &&
- !gpr_cv_cancellable_wait(&s->cv, &s->mu, abs_deadline, c));
- gpr_mu_unlock(&s->mu);
- }
- return result;
-}
-
void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
index 61572b9a8e..6f078cd4bb 100644
--- a/src/core/support/sync_posix.c
+++ b/src/core/support/sync_posix.c
@@ -63,7 +63,8 @@ void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }
int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
int err = 0;
- if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) {
+ if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) ==
+ 0) {
err = pthread_cond_wait(cv, mu);
} else {
struct timespec abs_deadline_ts;
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index 54f84a46ac..df23492171 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -83,7 +83,8 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
int timeout = 0;
DWORD timeout_max_ms;
mu->locked = 0;
- if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) {
+ if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) ==
+ 0) {
SleepConditionVariableCS(cv, &mu->cs, INFINITE);
} else {
gpr_timespec now = gpr_now(abs_deadline.clock_type);
diff --git a/src/core/support/thd.c b/src/core/support/thd.c
index ec308f3119..32c0db5b66 100644
--- a/src/core/support/thd.c
+++ b/src/core/support/thd.c
@@ -37,9 +37,7 @@
#include <grpc/support/thd.h>
-enum {
- GPR_THD_JOINABLE = 1
-};
+enum { GPR_THD_JOINABLE = 1 };
gpr_thd_options gpr_thd_options_default(void) {
gpr_thd_options options;
diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h
index 4683c37742..1508c4691f 100644
--- a/src/core/support/thd_internal.h
+++ b/src/core/support/thd_internal.h
@@ -36,4 +36,4 @@
/* Internal interfaces between modules within the gpr support library. */
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
index fa4eb50556..c36d94d044 100644
--- a/src/core/support/thd_posix.c
+++ b/src/core/support/thd_posix.c
@@ -69,9 +69,11 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
GPR_ASSERT(pthread_attr_init(&attr) == 0);
if (gpr_thd_options_is_detached(options)) {
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
+ 0);
} else {
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0);
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
+ 0);
}
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
@@ -82,12 +84,8 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
return thread_started;
}
-gpr_thd_id gpr_thd_currentid(void) {
- return (gpr_thd_id)pthread_self();
-}
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
-void gpr_thd_join(gpr_thd_id t) {
- pthread_join((pthread_t)t, NULL);
-}
+void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); }
#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
index 4fa3907444..a9db180c1b 100644
--- a/src/core/support/thd_win32.c
+++ b/src/core/support/thd_win32.c
@@ -105,9 +105,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
return handle != NULL;
}
-gpr_thd_id gpr_thd_currentid(void) {
- return (gpr_thd_id)g_thd_info;
-}
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
void gpr_thd_join(gpr_thd_id t) {
struct thd_info *info = (struct thd_info *)t;
diff --git a/src/core/support/time.c b/src/core/support/time.c
index b523ae01cc..929adac918 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -315,5 +315,6 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
return gpr_time_add(gpr_now(clock_type), t);
}
- return gpr_time_add(gpr_now(clock_type), gpr_time_sub(t, gpr_now(t.clock_type)));
+ return gpr_time_add(gpr_now(clock_type),
+ gpr_time_sub(t, gpr_now(t.clock_type)));
}
diff --git a/src/core/support/tls_pthread.c b/src/core/support/tls_pthread.c
index f2e76a553f..2d28226fc4 100644
--- a/src/core/support/tls_pthread.c
+++ b/src/core/support/tls_pthread.c
@@ -38,7 +38,7 @@
#include <grpc/support/tls.h>
gpr_intptr gpr_tls_set(struct gpr_pthread_thread_local *tls, gpr_intptr value) {
- GPR_ASSERT(0 == pthread_setspecific(tls->key, (void*)value));
+ GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value));
return value;
}
diff --git a/src/core/surface/byte_buffer_queue.h b/src/core/surface/byte_buffer_queue.h
index f01958984f..2c3b22d24e 100644
--- a/src/core/surface/byte_buffer_queue.h
+++ b/src/core/surface/byte_buffer_queue.h
@@ -59,4 +59,4 @@ int grpc_bbq_empty(grpc_byte_buffer_queue *q);
void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *bb);
size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 5839d3ac2e..33f277da46 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -39,6 +39,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/iomgr/alarm.h"
@@ -242,6 +243,9 @@ struct grpc_call {
/* Compression algorithm for the call */
grpc_compression_algorithm compression_algorithm;
+ /* Supported encodings (compression algorithms), a bitset */
+ gpr_uint32 encodings_accepted_by_peer;
+
/* Contexts for various subsystems (security, tracing, ...). */
grpc_call_context_element context[GRPC_CONTEXT_COUNT];
@@ -272,7 +276,8 @@ struct grpc_call {
/** completion events - for completion queue use */
grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS];
- /** siblings: children of the same parent form a list, and this list is protected under
+ /** siblings: children of the same parent form a list, and this list is
+ protected under
parent->mu */
grpc_call *sibling_next;
grpc_call *sibling_prev;
@@ -394,7 +399,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
} else {
call->sibling_next = parent_call->first_child;
call->sibling_prev = parent_call->first_child->sibling_prev;
- call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call;
+ call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
+ call;
}
gpr_mu_unlock(&parent_call->mu);
@@ -532,6 +538,45 @@ grpc_compression_algorithm grpc_call_get_compression_algorithm(
return call->compression_algorithm;
}
+static void set_encodings_accepted_by_peer(
+ grpc_call *call, const gpr_slice accept_encoding_slice) {
+ size_t i;
+ grpc_compression_algorithm algorithm;
+ gpr_slice_buffer accept_encoding_parts;
+
+ gpr_slice_buffer_init(&accept_encoding_parts);
+ gpr_slice_split(accept_encoding_slice, ", ", &accept_encoding_parts);
+
+ /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already
+ * zeroes the whole grpc_call */
+ /* Always support no compression */
+ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
+ for (i = 0; i < accept_encoding_parts.count; i++) {
+ const gpr_slice *accept_encoding_entry_slice =
+ &accept_encoding_parts.slices[i];
+ if (grpc_compression_algorithm_parse(
+ (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice),
+ GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
+ GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
+ } else {
+ char *accept_encoding_entry_str =
+ gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
+ gpr_log(GPR_ERROR,
+ "Invalid entry in accept encoding metadata: '%s'. Ignoring.",
+ accept_encoding_entry_str);
+ gpr_free(accept_encoding_entry_str);
+ }
+ }
+}
+
+gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) {
+ return call->encodings_accepted_by_peer;
+}
+
+gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) {
+ return call->incoming_message_flags;
+}
+
static void set_status_details(grpc_call *call, status_source source,
grpc_mdstr *status) {
if (call->status[source].details != NULL) {
@@ -964,7 +1009,7 @@ static void call_on_done_recv(void *pc, int success) {
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);
+ grpc_call_cancel(child_call, NULL);
GRPC_CALL_INTERNAL_UNREF(child_call, "propagate_cancel", 0);
}
child_call = next_child_call;
@@ -1265,18 +1310,22 @@ void grpc_call_destroy(grpc_call *c) {
c->cancel_alarm |= c->have_alarm;
cancel = c->read_state != READ_STATE_STREAM_CLOSED;
unlock(c);
- if (cancel) grpc_call_cancel(c);
+ if (cancel) grpc_call_cancel(c, NULL);
GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1);
}
-grpc_call_error grpc_call_cancel(grpc_call *call) {
- return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled");
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
+ GPR_ASSERT(!reserved);
+ return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
+ NULL);
}
grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
grpc_status_code status,
- const char *description) {
+ const char *description,
+ void *reserved) {
grpc_call_error r;
+ (void)reserved;
lock(c);
r = cancel_with_status(c, status, description);
unlock(c);
@@ -1404,10 +1453,11 @@ static gpr_uint32 decode_compression(grpc_mdelem *md) {
void *user_data = grpc_mdelem_get_user_data(md, destroy_compression);
if (user_data) {
algorithm =
- ((grpc_compression_level)(gpr_intptr)user_data) - COMPRESS_OFFSET;
+ ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET;
} else {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
- if (!grpc_compression_algorithm_parse(md_c_str, &algorithm)) {
+ if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
+ &algorithm)) {
gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
assert(0);
}
@@ -1436,6 +1486,9 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
} else if (key ==
grpc_channel_get_compression_algorithm_string(call->channel)) {
set_compression_algorithm(call, decode_compression(md));
+ } else if (key == grpc_channel_get_encodings_accepted_by_peer_string(
+ call->channel)) {
+ set_encodings_accepted_by_peer(call, md->value->slice);
} else {
dest = &call->buffered_metadata[is_trailing];
if (dest->count == dest->capacity) {
@@ -1513,7 +1566,7 @@ static int are_write_flags_valid(gpr_uint32 flags) {
}
grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
- size_t nops, void *tag) {
+ size_t nops, void *tag, void *reserved) {
grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT];
size_t in;
size_t out;
@@ -1521,6 +1574,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
grpc_ioreq *req;
void (*finish_func)(grpc_call *, int, void *) = finish_batch;
+ if (reserved != NULL) return GRPC_CALL_ERROR;
+
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
if (nops == 0) {
@@ -1534,12 +1589,13 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
/* rewrite batch ops into ioreq ops */
for (in = 0, out = 0; in < nops; in++) {
op = &ops[in];
+ if (op->reserved != NULL) return GRPC_CALL_ERROR;
switch (op->op) {
case GRPC_OP_SEND_INITIAL_METADATA:
/* Flag validation: currently allow no flags */
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_INITIAL_METADATA;
req->data.send_metadata.count = op->data.send_initial_metadata.count;
req->data.send_metadata.metadata =
@@ -1554,7 +1610,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
return GRPC_CALL_ERROR_INVALID_MESSAGE;
}
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_MESSAGE;
req->data.send_message = op->data.send_message;
req->flags = op->flags;
@@ -1566,7 +1622,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
return GRPC_CALL_ERROR_NOT_ON_SERVER;
}
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_CLOSE;
req->flags = op->flags;
break;
@@ -1577,7 +1633,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
return GRPC_CALL_ERROR_NOT_ON_CLIENT;
}
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_TRAILING_METADATA;
req->flags = op->flags;
req->data.send_metadata.count =
@@ -1585,7 +1641,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
req->data.send_metadata.metadata =
op->data.send_status_from_server.trailing_metadata;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_STATUS;
req->data.send_status.code = op->data.send_status_from_server.status;
req->data.send_status.details =
@@ -1595,7 +1651,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
op->data.send_status_from_server.status_details, 0)
: NULL;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_SEND_CLOSE;
break;
case GRPC_OP_RECV_INITIAL_METADATA:
@@ -1605,7 +1661,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
return GRPC_CALL_ERROR_NOT_ON_SERVER;
}
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
req->data.recv_metadata = op->data.recv_initial_metadata;
req->data.recv_metadata->count = 0;
@@ -1615,7 +1671,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
/* Flag validation: currently allow no flags */
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_MESSAGE;
req->data.recv_message = op->data.recv_message;
req->flags = op->flags;
@@ -1627,26 +1683,26 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
return GRPC_CALL_ERROR_NOT_ON_SERVER;
}
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_STATUS;
req->flags = op->flags;
req->data.recv_status.set_value = set_status_value_directly;
req->data.recv_status.user_data = op->data.recv_status_on_client.status;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_STATUS_DETAILS;
req->data.recv_status_details.details =
op->data.recv_status_on_client.status_details;
req->data.recv_status_details.details_capacity =
op->data.recv_status_on_client.status_details_capacity;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_TRAILING_METADATA;
req->data.recv_metadata =
op->data.recv_status_on_client.trailing_metadata;
req->data.recv_metadata->count = 0;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break;
@@ -1654,14 +1710,14 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
/* Flag validation: currently allow no flags */
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_STATUS;
req->flags = op->flags;
req->data.recv_status.set_value = set_cancelled_value;
req->data.recv_status.user_data =
op->data.recv_close_on_server.cancelled;
req = &reqs[out++];
- if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
+ if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG;
req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break;
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 75bdbce980..00638e43b5 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -38,6 +38,10 @@
#include "src/core/channel/context.h"
#include <grpc/grpc.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Primitive operation types - grpc_op's get rewritten into these */
typedef enum {
GRPC_IOREQ_RECV_INITIAL_METADATA,
@@ -162,4 +166,19 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
gpr_uint8 grpc_call_is_client(grpc_call *call);
+grpc_compression_algorithm grpc_call_get_compression_algorithm(
+ const grpc_call *call);
+
+gpr_uint32 grpc_call_get_message_flags(const grpc_call *call);
+
+/** Returns a bitset for the encodings (compression algorithms) supported by \a
+ * call's peer.
+ *
+ * To be indexed by grpc_compression_algorithm enum values. */
+gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
index 7bf8cafc24..5a3ef1e5f4 100644
--- a/src/core/surface/call_log_batch.c
+++ b/src/core/surface/call_log_batch.c
@@ -41,7 +41,7 @@ int grpc_trace_batch = 0;
static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
size_t i;
- for(i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
gpr_strvec_add(b, gpr_strdup("\nkey="));
gpr_strvec_add(b, gpr_strdup(md[i].key));
@@ -113,8 +113,9 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
char *tmp;
size_t i;
gpr_log(file, line, severity,
- "grpc_call_start_batch(call=%p, ops=%p, nops=%d, tag=%p)", call, ops, nops, tag);
- for(i = 0; i < nops; i++) {
+ "grpc_call_start_batch(call=%p, ops=%p, nops=%d, tag=%p)", call, ops,
+ nops, tag);
+ for (i = 0; i < nops; i++) {
tmp = grpc_op_string(&ops[i]);
gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
gpr_free(tmp);
@@ -123,8 +124,7 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
void grpc_server_log_request_call(char *file, int line,
gpr_log_severity severity,
- grpc_server *server,
- grpc_call **call,
+ grpc_server *server, grpc_call **call,
grpc_call_details *details,
grpc_metadata_array *initial_metadata,
grpc_completion_queue *cq_bound_to_call,
@@ -133,8 +133,9 @@ void grpc_server_log_request_call(char *file, int line,
gpr_log(file, line, severity,
"grpc_server_request_call(server=%p, call=%p, details=%p, "
"initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
- "tag=%p)", server, call, details, initial_metadata,
- cq_bound_to_call, cq_for_notification, tag);
+ "tag=%p)",
+ server, call, details, initial_metadata, cq_bound_to_call,
+ cq_for_notification, tag);
}
void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity,
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 8692aa3903..e50251566d 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -66,6 +66,7 @@ struct grpc_channel {
/** mdstr for the grpc-status key */
grpc_mdstr *grpc_status_string;
grpc_mdstr *grpc_compression_algorithm_string;
+ grpc_mdstr *grpc_encodings_accepted_by_peer_string;
grpc_mdstr *grpc_message_string;
grpc_mdstr *path_string;
grpc_mdstr *authority_string;
@@ -104,7 +105,10 @@ grpc_channel *grpc_channel_create_from_filters(
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0);
channel->grpc_compression_algorithm_string =
grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
- channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0);
+ channel->grpc_encodings_accepted_by_peer_string =
+ grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0);
+ channel->grpc_message_string =
+ grpc_mdstr_from_string(mdctx, "grpc-message", 0);
for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
char buf[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(i, buf);
@@ -159,7 +163,7 @@ static grpc_call *grpc_channel_create_call_internal(
send_metadata[num_metadata++] = authority_mdelem;
}
- return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
+ return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
send_metadata, num_metadata, deadline);
}
@@ -168,28 +172,34 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
gpr_uint32 propagation_mask,
grpc_completion_queue *cq,
const char *method, const char *host,
- gpr_timespec deadline) {
+ gpr_timespec deadline, void *reserved) {
+ GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, cq,
grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
grpc_mdstr_from_string(channel->metadata_context, method, 0)),
- host ?
- grpc_mdelem_from_metadata_strings(
- channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
- grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL,
+ host ? grpc_mdelem_from_metadata_strings(
+ channel->metadata_context,
+ GRPC_MDSTR_REF(channel->authority_string),
+ grpc_mdstr_from_string(channel->metadata_context, host, 0))
+ : NULL,
deadline);
}
void *grpc_channel_register_call(grpc_channel *channel, const char *method,
- const char *host) {
+ const char *host, void *reserved) {
registered_call *rc = gpr_malloc(sizeof(registered_call));
+ GPR_ASSERT(!reserved);
rc->path = grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
grpc_mdstr_from_string(channel->metadata_context, method, 0));
- rc->authority = host ? grpc_mdelem_from_metadata_strings(
- channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
- grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL;
+ rc->authority =
+ host ? grpc_mdelem_from_metadata_strings(
+ channel->metadata_context,
+ GRPC_MDSTR_REF(channel->authority_string),
+ grpc_mdstr_from_string(channel->metadata_context, host, 0))
+ : NULL;
gpr_mu_lock(&channel->registered_call_mu);
rc->next = channel->registered_calls;
channel->registered_calls = rc;
@@ -200,11 +210,12 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
grpc_call *grpc_channel_create_registered_call(
grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
grpc_completion_queue *completion_queue, void *registered_call_handle,
- gpr_timespec deadline) {
+ gpr_timespec deadline, void *reserved) {
registered_call *rc = registered_call_handle;
+ GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
- channel, parent_call, propagation_mask, completion_queue,
- GRPC_MDELEM_REF(rc->path),
+ channel, parent_call, propagation_mask, completion_queue,
+ GRPC_MDELEM_REF(rc->path),
rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
}
@@ -227,6 +238,7 @@ static void destroy_channel(void *p, int ok) {
}
GRPC_MDSTR_UNREF(channel->grpc_status_string);
GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string);
+ GRPC_MDSTR_UNREF(channel->grpc_encodings_accepted_by_peer_string);
GRPC_MDSTR_UNREF(channel->grpc_message_string);
GRPC_MDSTR_UNREF(channel->path_string);
GRPC_MDSTR_UNREF(channel->authority_string);
@@ -287,6 +299,11 @@ grpc_mdstr *grpc_channel_get_compression_algorithm_string(
return channel->grpc_compression_algorithm_string;
}
+grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
+ grpc_channel *channel) {
+ return channel->grpc_encodings_accepted_by_peer_string;
+}
+
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
return GRPC_MDELEM_REF(channel->grpc_status_elem[i]);
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 9e0646efaa..f271616f60 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -56,6 +56,8 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_compression_algorithm_string(
grpc_channel *channel);
+grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
+ grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index 1223706457..88a7c16598 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -77,9 +77,10 @@ typedef struct {
} state_watcher;
static void delete_state_watcher(state_watcher *w) {
- grpc_channel_element *client_channel_elem =
- grpc_channel_stack_last_element(grpc_channel_get_channel_stack(w->channel));
- grpc_client_channel_del_interested_party(client_channel_elem, grpc_cq_pollset(w->cq));
+ grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
+ grpc_channel_get_channel_stack(w->channel));
+ grpc_client_channel_del_interested_party(client_channel_elem,
+ grpc_cq_pollset(w->cq));
GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity");
gpr_mu_destroy(&w->mu);
gpr_free(w);
@@ -166,9 +167,9 @@ void grpc_channel_watch_connectivity_state(
w->tag = tag;
w->channel = channel;
- grpc_alarm_init(
- &w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
- timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
+ grpc_alarm_init(&w->alarm,
+ gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+ timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
if (client_channel_elem->filter != &grpc_client_channel_filter) {
gpr_log(GPR_ERROR,
@@ -178,7 +179,8 @@ void grpc_channel_watch_connectivity_state(
grpc_iomgr_add_delayed_callback(&w->on_complete, 1);
} else {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_connectivity");
- grpc_client_channel_add_interested_party(client_channel_elem, grpc_cq_pollset(cq));
+ grpc_client_channel_add_interested_party(client_channel_elem,
+ grpc_cq_pollset(cq));
grpc_client_channel_watch_connectivity_state(client_channel_elem, &w->state,
&w->on_complete);
}
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 4d01be3d7d..1b3707a091 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -156,7 +156,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
- connect to it (trying alternatives as presented)
- perform handshakes */
grpc_channel *grpc_insecure_channel_create(const char *target,
- const grpc_channel_args *args) {
+ const grpc_channel_args *args,
+ void *reserved) {
grpc_channel *channel = NULL;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
@@ -164,6 +165,7 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
subchannel_factory *f;
grpc_mdctx *mdctx = grpc_mdctx_create();
int n = 0;
+ GPR_ASSERT(!reserved);
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 36d69cfe5f..77443a7ae8 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -69,8 +69,9 @@ struct grpc_completion_queue {
plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
};
-grpc_completion_queue *grpc_completion_queue_create(void) {
+grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
+ GPR_ASSERT(!reserved);
memset(cc, 0, sizeof(*cc));
/* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cc->pending_events, 1);
@@ -166,9 +167,10 @@ void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
- gpr_timespec deadline) {
+ gpr_timespec deadline, void *reserved) {
grpc_event ret;
grpc_pollset_worker worker;
+ GPR_ASSERT(!reserved);
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
@@ -232,11 +234,12 @@ static void del_plucker(grpc_completion_queue *cc, void *tag,
}
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
- gpr_timespec deadline) {
+ gpr_timespec deadline, void *reserved) {
grpc_event ret;
grpc_cq_completion *c;
grpc_cq_completion *prev;
grpc_pollset_worker worker;
+ GPR_ASSERT(!reserved);
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
@@ -268,8 +271,9 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
break;
}
if (!add_plucker(cc, tag, &worker)) {
- gpr_log(GPR_DEBUG,
- "Too many outstanding grpc_completion_queue_pluck calls: maximum is %d",
+ gpr_log(GPR_DEBUG,
+ "Too many outstanding grpc_completion_queue_pluck calls: maximum "
+ "is %d",
GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
memset(&ret, 0, sizeof(ret));
diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h
index e8a8f93518..07c474e3a0 100644
--- a/src/core/surface/event_string.h
+++ b/src/core/surface/event_string.h
@@ -39,4 +39,4 @@
/* Returns a string describing an event. Must be later freed with gpr_free() */
char *grpc_event_string(grpc_event *ev);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index 442bc72f21..d9044549f2 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -33,8 +33,11 @@
#include <grpc/support/port_platform.h>
+#include <memory.h>
+
#include <grpc/census.h>
#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/time.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/resolver_registry.h"
@@ -49,6 +52,8 @@
#include "src/core/transport/chttp2_transport.h"
#include "src/core/transport/connectivity_state.h"
+#define MAX_PLUGINS 128
+
static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
static int g_initializations;
@@ -58,7 +63,23 @@ static void do_basic_init(void) {
g_initializations = 0;
}
+typedef struct grpc_plugin {
+ void (*init)();
+ void (*destroy)();
+} grpc_plugin;
+
+static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
+static int g_number_of_plugins = 0;
+
+void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
+ GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
+ g_all_of_the_plugins[g_number_of_plugins].init = init;
+ g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
+ g_number_of_plugins++;
+}
+
void grpc_init(void) {
+ int i;
gpr_once_init(&g_basic_init, do_basic_init);
gpr_mu_lock(&g_init_mu);
@@ -87,11 +108,17 @@ void grpc_init(void) {
}
}
grpc_timers_global_init();
+ for (i = 0; i < g_number_of_plugins; i++) {
+ if (g_all_of_the_plugins[i].init != NULL) {
+ g_all_of_the_plugins[i].init();
+ }
+ }
}
gpr_mu_unlock(&g_init_mu);
}
void grpc_shutdown(void) {
+ int i;
gpr_mu_lock(&g_init_mu);
if (--g_initializations == 0) {
grpc_iomgr_shutdown();
@@ -99,6 +126,11 @@ void grpc_shutdown(void) {
grpc_timers_global_destroy();
grpc_tracer_shutdown();
grpc_resolver_registry_shutdown();
+ for (i = 0; i < g_number_of_plugins; i++) {
+ if (g_all_of_the_plugins[i].destroy != NULL) {
+ g_all_of_the_plugins[i].destroy();
+ }
+ }
}
gpr_mu_unlock(&g_init_mu);
}
diff --git a/src/core/surface/init.h b/src/core/surface/init.h
index 416874020d..771c30f412 100644
--- a/src/core/surface/init.h
+++ b/src/core/surface/init.h
@@ -37,4 +37,4 @@
void grpc_security_pre_init(void);
int grpc_is_initialized(void);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */
diff --git a/src/core/surface/init_unsecure.c b/src/core/surface/init_unsecure.c
index ddb70cef8e..630d564a7d 100644
--- a/src/core/surface/init_unsecure.c
+++ b/src/core/surface/init_unsecure.c
@@ -33,5 +33,4 @@
#include "src/core/surface/init.h"
-void grpc_security_pre_init(void) {
-}
+void grpc_security_pre_init(void) {}
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index c4215a2cfb..80704cbf67 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -50,6 +50,8 @@ typedef struct {
typedef struct {
grpc_mdctx *mdctx;
grpc_channel *master;
+ grpc_status_code error_code;
+ const char *error_message;
} channel_data;
static void lame_start_transport_stream_op(grpc_call_element *elem,
@@ -64,11 +66,11 @@ static void lame_start_transport_stream_op(grpc_call_element *elem,
if (op->recv_ops != NULL) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
grpc_metadata_batch mdb;
- gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp);
+ gpr_ltoa(chand->error_code, tmp);
calld->status.md =
grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp);
calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message",
- "Rpc sent on a lame channel.");
+ chand->error_message);
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
@@ -138,8 +140,21 @@ static const grpc_channel_filter lame_filter = {
"lame-client",
};
-grpc_channel *grpc_lame_client_channel_create(const char *target) {
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
+
+grpc_channel *grpc_lame_client_channel_create(const char *target,
+ grpc_status_code error_code,
+ const char *error_message) {
+ grpc_channel *channel;
+ grpc_channel_element *elem;
+ channel_data *chand;
static const grpc_channel_filter *filters[] = {&lame_filter};
- return grpc_channel_create_from_filters(target, filters, 1, NULL,
- grpc_mdctx_create(), 1);
+ channel = grpc_channel_create_from_filters(target, filters, 1, NULL,
+ grpc_mdctx_create(), 1);
+ elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
+ GPR_ASSERT(elem->filter == &lame_filter);
+ chand = (channel_data *)elem->channel_data;
+ chand->error_code = error_code;
+ chand->error_message = error_message;
+ return channel;
}
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 943bddfc0c..cf204e112b 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -200,13 +200,17 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
if (grpc_find_security_connector_in_args(args) != NULL) {
gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
- return grpc_lame_client_channel_create(target);
+ return grpc_lame_client_channel_create(
+ target, GRPC_STATUS_INVALID_ARGUMENT,
+ "Security connector exists in channel args.");
}
if (grpc_credentials_create_security_connector(
creds, target, args, NULL, &connector, &new_args_from_connector) !=
GRPC_SECURITY_OK) {
- return grpc_lame_client_channel_create(target);
+ return grpc_lame_client_channel_create(
+ target, GRPC_STATUS_INVALID_ARGUMENT,
+ "Failed to create security connector.");
}
mdctx = grpc_mdctx_create();
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 22d399cf1f..145fa6ee1a 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -712,7 +712,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
chand->server = NULL;
chand->channel = NULL;
chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0);
- chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0);
+ chand->authority_key =
+ grpc_mdstr_from_string(metadata_context, ":authority", 0);
chand->next = chand->prev = chand;
chand->registered_methods = NULL;
chand->connectivity_state = GRPC_CHANNEL_IDLE;
@@ -761,8 +762,10 @@ static const grpc_channel_filter server_surface_filter = {
};
void grpc_server_register_completion_queue(grpc_server *server,
- grpc_completion_queue *cq) {
+ grpc_completion_queue *cq,
+ void *reserved) {
size_t i, n;
+ GPR_ASSERT(!reserved);
for (i = 0; i < server->cq_count; i++) {
if (server->cqs[i] == cq) return;
}
@@ -971,6 +974,11 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
grpc_transport_perform_op(transport, &op);
}
+void done_published_shutdown(void *done_arg, grpc_cq_completion *storage) {
+ (void) done_arg;
+ gpr_free(storage);
+}
+
void grpc_server_shutdown_and_notify(grpc_server *server,
grpc_completion_queue *cq, void *tag) {
listener *l;
@@ -982,6 +990,12 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
/* lock, and gather up some stuff to do */
gpr_mu_lock(&server->mu_global);
grpc_cq_begin_op(cq);
+ if (server->shutdown_published) {
+ grpc_cq_end_op(cq, tag, 1, done_published_shutdown, NULL,
+ gpr_malloc(sizeof(grpc_cq_completion)));
+ gpr_mu_unlock(&server->mu_global);
+ return;
+ }
server->shutdown_tags =
gpr_realloc(server->shutdown_tags,
sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
@@ -1131,6 +1145,7 @@ grpc_call_error grpc_server_request_call(
return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
}
grpc_cq_begin_op(cq_for_notification);
+ details->reserved = NULL;
rc->type = BATCH_CALL;
rc->server = server;
rc->tag = tag;
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
index 1e26c67693..fc7ae820f5 100644
--- a/src/core/surface/server_create.c
+++ b/src/core/surface/server_create.c
@@ -36,8 +36,9 @@
#include "src/core/surface/server.h"
#include "src/core/channel/compress_filter.h"
-grpc_server *grpc_server_create(const grpc_channel_args *args) {
+grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
const grpc_channel_filter *filters[] = {&grpc_compress_filter};
+ (void)reserved;
return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters),
args);
}
diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h
index 01302bb5d4..2b4728e2b4 100644
--- a/src/core/surface/surface_trace.h
+++ b/src/core/surface/surface_trace.h
@@ -40,10 +40,10 @@
extern int grpc_surface_trace;
#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \
- if (grpc_surface_trace) { \
+ if (grpc_surface_trace) { \
char *_ev = grpc_event_string(event); \
gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \
gpr_free(_ev); \
}
-#endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index 40bf2ebd79..474c3d5ee6 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -92,10 +92,10 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_type = *cur;
switch (p->frame_type) {
case 0:
- p->is_frame_compressed = 0; /* GPR_FALSE */
+ p->is_frame_compressed = 0; /* GPR_FALSE */
break;
case 1:
- p->is_frame_compressed = 1; /* GPR_TRUE */
+ p->is_frame_compressed = 1; /* GPR_TRUE */
break;
default:
gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index d84960009b..dc5eb18e42 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -177,10 +177,9 @@ void grpc_chttp2_publish_reads(
"parsed", transport_parsing, stream_global, max_recv_bytes,
-(gpr_int64)stream_parsing->incoming_window_delta);
stream_global->incoming_window -= stream_parsing->incoming_window_delta;
- GPR_ASSERT(stream_global->max_recv_bytes >=
- stream_parsing->incoming_window_delta);
- stream_global->max_recv_bytes -=
- stream_parsing->incoming_window_delta;
+ GPR_ASSERT(stream_global->max_recv_bytes >=
+ stream_parsing->incoming_window_delta);
+ stream_global->max_recv_bytes -= stream_parsing->incoming_window_delta;
stream_parsing->incoming_window_delta = 0;
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
}
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
index 9c3ad7a777..38c6052f9c 100644
--- a/src/core/transport/chttp2/stream_lists.c
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -363,7 +363,7 @@ void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
}
int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t,
- grpc_chttp2_stream *s) {
+ grpc_chttp2_stream *s) {
stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS);
}
diff --git a/src/core/transport/chttp2/stream_map.c b/src/core/transport/chttp2/stream_map.c
index 0ec2f27291..bd16153ed1 100644
--- a/src/core/transport/chttp2/stream_map.c
+++ b/src/core/transport/chttp2/stream_map.c
@@ -123,8 +123,7 @@ void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src,
dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *));
}
memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(gpr_uint32));
- memcpy(dst->values + dst->count, src->values,
- src->count * sizeof(void*));
+ memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *));
dst->count += src->count;
dst->free += src->free;
src->count = 0;
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index b55e81fdca..123061b3fc 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -112,13 +112,18 @@ int grpc_chttp2_unlocking_check_writes(
}
}
- if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
- stream_writing->announce_window = stream_global->unannounced_incoming_window;
- GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
- incoming_window, stream_global->unannounced_incoming_window);
- GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
- unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
- stream_global->incoming_window += stream_global->unannounced_incoming_window;
+ if (!stream_global->read_closed &&
+ stream_global->unannounced_incoming_window > 0) {
+ stream_writing->announce_window =
+ stream_global->unannounced_incoming_window;
+ GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+ "write", transport_global, stream_global, incoming_window,
+ stream_global->unannounced_incoming_window);
+ GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+ "write", transport_global, stream_global, unannounced_incoming_window,
+ -(gpr_int64)stream_global->unannounced_incoming_window);
+ stream_global->incoming_window +=
+ stream_global->unannounced_incoming_window;
stream_global->unannounced_incoming_window = 0;
grpc_chttp2_list_add_incoming_window_updated(transport_global,
stream_global);
@@ -179,18 +184,20 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
while (
grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
- if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
+ if (stream_writing->sopb.nops > 0 ||
+ stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops,
stream_writing->send_closed != GRPC_DONT_SEND_CLOSED,
- stream_writing->id, &transport_writing->hpack_compressor,
+ stream_writing->id,
+ &transport_writing->hpack_compressor,
&transport_writing->outbuf);
stream_writing->sopb.nops = 0;
}
if (stream_writing->announce_window > 0) {
gpr_slice_buffer_add(
&transport_writing->outbuf,
- grpc_chttp2_window_update_create(
- stream_writing->id, stream_writing->announce_window));
+ grpc_chttp2_window_update_create(stream_writing->id,
+ stream_writing->announce_window));
stream_writing->announce_window = 0;
}
if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index a9f91b64d5..1bbd210e46 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -116,7 +116,7 @@ static void close_from_api(grpc_chttp2_transport_global *transport_global,
static void add_to_pollset_locked(grpc_chttp2_transport *t,
grpc_pollset *pollset);
static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
- grpc_pollset_set *pollset_set);
+ grpc_pollset_set *pollset_set);
/** Start new streams that have been created if we can */
static void maybe_start_some_streams(
@@ -368,11 +368,10 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
s->global.outgoing_window =
t->global.settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->global.max_recv_bytes =
- s->parsing.incoming_window =
+ s->global.max_recv_bytes = s->parsing.incoming_window =
s->global.incoming_window =
- t->global.settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+ t->global.settings[GRPC_SENT_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
*t->accepting_stream = s;
grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
s->global.in_stream_map = 1;
@@ -580,7 +579,7 @@ static void maybe_start_some_streams(
stream_global->incoming_window =
transport_global->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- stream_global->max_recv_bytes =
+ stream_global->max_recv_bytes =
GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes);
grpc_chttp2_stream_map_add(
&TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
@@ -590,7 +589,6 @@ static void maybe_start_some_streams(
grpc_chttp2_list_add_incoming_window_updated(transport_global,
stream_global);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
-
}
/* cancel out streams that will never be started */
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@@ -648,12 +646,14 @@ static void perform_stream_op_locked(
stream_global->publish_sopb->nops = 0;
stream_global->publish_state = op->recv_state;
if (stream_global->max_recv_bytes < op->max_recv_bytes) {
- GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("op", transport_global, stream_global,
- max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes);
+ GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+ "op", transport_global, stream_global, max_recv_bytes,
+ op->max_recv_bytes - stream_global->max_recv_bytes);
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
"op", transport_global, stream_global, unannounced_incoming_window,
op->max_recv_bytes - stream_global->max_recv_bytes);
- stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes;
+ stream_global->unannounced_incoming_window +=
+ op->max_recv_bytes - stream_global->max_recv_bytes;
stream_global->max_recv_bytes = op->max_recv_bytes;
}
grpc_chttp2_incoming_metadata_live_op_buffer_end(
@@ -1175,7 +1175,7 @@ static void add_to_pollset_locked(grpc_chttp2_transport *t,
}
static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
- grpc_pollset_set *pollset_set) {
+ grpc_pollset_set *pollset_set) {
if (t->ep) {
grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
}
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 44d32b6cb2..f92e87e9dd 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -133,8 +133,8 @@ static void unlock(grpc_mdctx *ctx) {
case), since otherwise we can be stuck waiting for a garbage collection
that will never happen. */
if (ctx->refs == 0) {
- /* uncomment if you're having trouble diagnosing an mdelem leak to make
- things clearer (slows down destruction a lot, however) */
+/* uncomment if you're having trouble diagnosing an mdelem leak to make
+ things clearer (slows down destruction a lot, however) */
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gc_mdtab(ctx);
#endif
@@ -311,7 +311,8 @@ static void slice_unref(void *p) {
unlock(ctx);
}
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) {
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str,
+ int canonicalize_key) {
if (canonicalize_key) {
size_t len;
size_t i;
@@ -522,9 +523,9 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
const char *value) {
- return grpc_mdelem_from_metadata_strings(ctx,
- grpc_mdstr_from_string(ctx, key, 0),
- grpc_mdstr_from_string(ctx, value, 0));
+ return grpc_mdelem_from_metadata_strings(
+ ctx, grpc_mdstr_from_string(ctx, key, 0),
+ grpc_mdstr_from_string(ctx, value, 0));
}
grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 15ef9bb555..a7af49ba55 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -95,7 +95,8 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
/* Constructors for grpc_mdstr instances; take a variety of data types that
clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization);
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str,
+ int perform_key_canonicalization);
/* Unrefs the slice. */
grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
@@ -179,4 +180,4 @@ void grpc_mdctx_unlock(grpc_mdctx *ctx);
#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index a5dfec9d50..038586d48e 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -203,8 +203,8 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
#endif /* NDEBUG */
void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
- batch->list.head = batch->list.tail = batch->garbage.head = batch->garbage.tail =
- NULL;
+ batch->list.head = batch->list.tail = batch->garbage.head =
+ batch->garbage.tail = NULL;
batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
@@ -258,6 +258,7 @@ static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
GPR_ASSERT(storage->md);
storage->prev = list->tail;
storage->next = NULL;
+ storage->reserved = NULL;
if (list->tail != NULL) {
list->tail->next = storage;
} else {
@@ -287,7 +288,7 @@ void grpc_metadata_batch_merge(grpc_metadata_batch *target,
}
void grpc_metadata_batch_move(grpc_metadata_batch *dst,
- grpc_metadata_batch *src) {
+ grpc_metadata_batch *src) {
*dst = *src;
memset(src, 0, sizeof(grpc_metadata_batch));
}
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index 227320cf2a..37f18b02d9 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -77,6 +77,7 @@ typedef struct grpc_linked_mdelem {
grpc_mdelem *md;
struct grpc_linked_mdelem *next;
struct grpc_linked_mdelem *prev;
+ void *reserved;
} grpc_linked_mdelem;
typedef struct grpc_mdelem_list {
diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
index 9ce1ddb95e..29127c4269 100644
--- a/src/core/tsi/fake_transport_security.c
+++ b/src/core/tsi/fake_transport_security.c
@@ -121,7 +121,7 @@ static void store32_little_endian(gpr_uint32 value, unsigned char* buf) {
buf[3] = (unsigned char)(value >> 24) & 0xFF;
buf[2] = (unsigned char)(value >> 16) & 0xFF;
buf[1] = (unsigned char)(value >> 8) & 0xFF;
- buf[0] = (unsigned char)(value) & 0xFF;
+ buf[0] = (unsigned char)(value)&0xFF;
}
static void tsi_fake_frame_reset(tsi_fake_frame* frame, int needs_draining) {
@@ -370,7 +370,8 @@ static void fake_protector_destroy(tsi_frame_protector* self) {
static const tsi_frame_protector_vtable frame_protector_vtable = {
fake_protector_protect, fake_protector_protect_flush,
- fake_protector_unprotect, fake_protector_destroy, };
+ fake_protector_unprotect, fake_protector_destroy,
+};
/* --- tsi_handshaker methods implementation. ---*/
@@ -393,7 +394,8 @@ static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
}
if (tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server",
+ gpr_log(GPR_INFO, "%s prepared %s.",
+ impl->is_client ? "Client" : "Server",
tsi_fake_handshake_message_to_string(impl->next_message_to_send));
}
impl->next_message_to_send = next_message_to_send;
@@ -493,7 +495,8 @@ static const tsi_handshaker_vtable handshaker_vtable = {
fake_handshaker_get_result,
fake_handshaker_extract_peer,
fake_handshaker_create_frame_protector,
- fake_handshaker_destroy, };
+ fake_handshaker_destroy,
+};
tsi_handshaker* tsi_create_fake_handshaker(int is_client) {
tsi_fake_handshaker* impl = calloc(1, sizeof(tsi_fake_handshaker));
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
index af9730b90e..1fa11349fb 100644
--- a/src/core/tsi/fake_transport_security.h
+++ b/src/core/tsi/fake_transport_security.h
@@ -58,4 +58,4 @@ tsi_frame_protector* tsi_create_fake_protector(
}
#endif
-#endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */
+#endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 609fc06ed5..0b416f6c9d 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -43,7 +43,7 @@
#include "src/core/tsi/transport_security.h"
#include <openssl/bio.h>
-#include <openssl/crypto.h> /* For OPENSSL_free */
+#include <openssl/crypto.h> /* For OPENSSL_free */
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
@@ -54,7 +54,6 @@
#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
-
/* Putting a macro like this and littering the source file with #if is really
bad practice.
TODO(jboeuf): refactor all the #if / #endif in a separate module. */
@@ -116,7 +115,7 @@ typedef struct {
/* --- Library Initialization. ---*/
static gpr_once init_openssl_once = GPR_ONCE_INIT;
-static gpr_mu *openssl_mutexes = NULL;
+static gpr_mu* openssl_mutexes = NULL;
static void openssl_locking_cb(int mode, int type, const char* file, int line) {
if (mode & CRYPTO_LOCK) {
@@ -195,7 +194,7 @@ static void ssl_info_callback(const SSL* ssl, int where, int ret) {
/* Returns 1 if name looks like an IP address, 0 otherwise.
This is a very rough heuristic as it does not handle IPV6 or things like:
0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */
-static int looks_like_ip_address(const char *name) {
+static int looks_like_ip_address(const char* name) {
size_t i;
size_t dot_count = 0;
size_t num_size = 0;
@@ -215,7 +214,6 @@ static int looks_like_ip_address(const char *name) {
return 1;
}
-
/* Gets the subject CN from an X509 cert. */
static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
size_t* utf8_size) {
@@ -630,7 +628,8 @@ static tsi_result build_alpn_protocol_name_list(
}
/* Safety check. */
if ((current < *protocol_name_list) ||
- ((gpr_uintptr)(current - *protocol_name_list) != *protocol_name_list_length)) {
+ ((gpr_uintptr)(current - *protocol_name_list) !=
+ *protocol_name_list_length)) {
return TSI_INTERNAL_ERROR;
}
return TSI_OK;
@@ -768,7 +767,8 @@ static void ssl_protector_destroy(tsi_frame_protector* self) {
static const tsi_frame_protector_vtable frame_protector_vtable = {
ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
- ssl_protector_destroy, };
+ ssl_protector_destroy,
+};
/* --- tsi_handshaker methods implementation. ---*/
@@ -948,7 +948,8 @@ static const tsi_handshaker_vtable handshaker_vtable = {
ssl_handshaker_get_result,
ssl_handshaker_extract_peer,
ssl_handshaker_create_frame_protector,
- ssl_handshaker_destroy, };
+ ssl_handshaker_destroy,
+};
/* --- tsi_ssl_handshaker_factory common methods. --- */
@@ -1075,9 +1076,11 @@ static void ssl_client_handshaker_factory_destroy(
free(impl);
}
-static int client_handshaker_factory_npn_callback(
- SSL* ssl, unsigned char** out, unsigned char* outlen,
- const unsigned char* in, unsigned int inlen, void* arg) {
+static int client_handshaker_factory_npn_callback(SSL* ssl, unsigned char** out,
+ unsigned char* outlen,
+ const unsigned char* in,
+ unsigned int inlen,
+ void* arg) {
tsi_ssl_client_handshaker_factory* factory =
(tsi_ssl_client_handshaker_factory*)arg;
return select_protocol_list((const unsigned char**)out, outlen,
@@ -1121,7 +1124,7 @@ static void ssl_server_handshaker_factory_destroy(
static int does_entry_match_name(const char* entry, size_t entry_length,
const char* name) {
- const char *dot;
+ const char* dot;
const char* name_subdomain = NULL;
size_t name_length = strlen(name);
size_t name_subdomain_length;
@@ -1153,7 +1156,7 @@ static int does_entry_match_name(const char* entry, size_t entry_length,
if (name_subdomain_length < 2) return 0;
name_subdomain++; /* Starts after the dot. */
name_subdomain_length--;
- entry += 2; /* Remove *. */
+ entry += 2; /* Remove *. */
entry_length -= 2;
dot = strchr(name_subdomain, '.');
if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) {
@@ -1170,7 +1173,7 @@ static int does_entry_match_name(const char* entry, size_t entry_length,
static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
void* arg) {
tsi_ssl_server_handshaker_factory* impl =
- (tsi_ssl_server_handshaker_factory*)arg;
+ (tsi_ssl_server_handshaker_factory*)arg;
size_t i = 0;
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (servername == NULL || strlen(servername) == 0) {
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index 4bf6c81b75..cdf4f294be 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -170,4 +170,4 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */
+#endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index 4cd0ec2cfb..34283f2f9c 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -108,4 +108,4 @@ char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */
}
#endif
-#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */
+#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
index e27e6b9fc9..03a51683a2 100644
--- a/src/core/tsi/transport_security_interface.h
+++ b/src/core/tsi/transport_security_interface.h
@@ -341,4 +341,4 @@ void tsi_handshaker_destroy(tsi_handshaker* self);
}
#endif
-#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */
+#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 1c2eecf786..17f31c22cb 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -67,18 +67,18 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
c_call = grpc_channel_create_registered_call(
c_channel_, context->propagate_from_call_,
context->propagation_options_.c_bitmask(), cq->cq(),
- method.channel_tag(), context->raw_deadline());
+ method.channel_tag(), context->raw_deadline(), nullptr);
} else {
const char* host_str = NULL;
if (!context->authority().empty()) {
- host_str = context->authority().c_str();
+ host_str = context->authority_.c_str();
} else if (!host_.empty()) {
host_str = host_.c_str();
}
c_call = grpc_channel_create_call(c_channel_, context->propagate_from_call_,
context->propagation_options_.c_bitmask(),
cq->cq(), method.name(), host_str,
- context->raw_deadline());
+ context->raw_deadline(), nullptr);
}
grpc_census_call_set_context(c_call, context->census_context());
GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call);
@@ -93,13 +93,13 @@ void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) {
GRPC_TIMER_BEGIN(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
ops->FillOps(cops, &nops);
GPR_ASSERT(GRPC_CALL_OK ==
- grpc_call_start_batch(call->call(), cops, nops, ops));
+ grpc_call_start_batch(call->call(), cops, nops, ops, nullptr));
GRPC_TIMER_END(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
}
void* Channel::RegisterMethod(const char* method) {
- return grpc_channel_register_call(c_channel_, method,
- host_.empty() ? NULL : host_.c_str());
+ return grpc_channel_register_call(
+ c_channel_, method, host_.empty() ? NULL : host_.c_str(), nullptr);
}
grpc_connectivity_state Channel::GetState(bool try_to_connect) {
@@ -116,6 +116,7 @@ class TagSaver GRPC_FINAL : public CompletionQueueTag {
delete this;
return true;
}
+
private:
void* tag_;
};
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index cb8e8d98d2..7e406ad788 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -58,9 +58,8 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface {
void* RegisterMethod(const char* method) GRPC_OVERRIDE;
Call CreateCall(const RpcMethod& method, ClientContext* context,
- CompletionQueue* cq) GRPC_OVERRIDE;
- void PerformOpsOnCall(CallOpSetInterface* ops,
- Call* call) GRPC_OVERRIDE;
+ CompletionQueue* cq) GRPC_OVERRIDE;
+ void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE;
grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE;
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index dd86e7b108..b8caa1eae4 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -77,19 +77,19 @@ void ClientContext::set_call(grpc_call* call,
channel_ = channel;
if (creds_ && !creds_->ApplyToCall(call_)) {
grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
- "Failed to set credentials to rpc.");
+ "Failed to set credentials to rpc.", nullptr);
}
}
void ClientContext::set_compression_algorithm(
grpc_compression_algorithm algorithm) {
- char* algorithm_name = NULL;
+ char* algorithm_name = nullptr;
if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.",
algorithm);
abort();
}
- GPR_ASSERT(algorithm_name != NULL);
+ GPR_ASSERT(algorithm_name != nullptr);
AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
}
@@ -102,7 +102,7 @@ std::shared_ptr<const AuthContext> ClientContext::auth_context() const {
void ClientContext::TryCancel() {
if (call_) {
- grpc_call_cancel(call_);
+ grpc_call_cancel(call_, nullptr);
}
}
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index 21d01b739d..5ae772f096 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -52,6 +52,8 @@ std::shared_ptr<ChannelInterface> CreateChannel(
user_agent_prefix.str());
return creds ? creds->CreateChannel(target, cp_args)
: std::shared_ptr<ChannelInterface>(
- new Channel(grpc_lame_client_channel_create(NULL)));
+ new Channel(grpc_lame_client_channel_create(
+ NULL, GRPC_STATUS_INVALID_ARGUMENT,
+ "Invalid credentials.")));
}
} // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index d8dcaa1436..2f9357b568 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -49,7 +49,7 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return std::shared_ptr<ChannelInterface>(new Channel(
- grpc_insecure_channel_create(target.c_str(), &channel_args)));
+ grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)));
}
// InsecureCredentials should not be applied to a call.
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index ddf69911b5..c2b8d43a15 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -59,4 +59,3 @@ class SecureCredentials GRPC_FINAL : public Credentials {
} // namespace grpc
#endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
-
diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc
index ba88983515..d3bfd5cb6b 100644
--- a/src/cpp/common/auth_property_iterator.cc
+++ b/src/cpp/common/auth_property_iterator.cc
@@ -64,8 +64,7 @@ AuthPropertyIterator AuthPropertyIterator::operator++(int) {
return tmp;
}
-bool AuthPropertyIterator::operator==(
- const AuthPropertyIterator& rhs) const {
+bool AuthPropertyIterator::operator==(const AuthPropertyIterator& rhs) const {
if (property_ == nullptr || rhs.property_ == nullptr) {
return property_ == rhs.property_;
} else {
@@ -73,8 +72,7 @@ bool AuthPropertyIterator::operator==(
}
}
-bool AuthPropertyIterator::operator!=(
- const AuthPropertyIterator& rhs) const {
+bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const {
return !operator==(rhs);
}
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index 593963f672..fca33f8f54 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -40,7 +40,9 @@
namespace grpc {
-CompletionQueue::CompletionQueue() { cq_ = grpc_completion_queue_create(); }
+CompletionQueue::CompletionQueue() {
+ cq_ = grpc_completion_queue_create(nullptr);
+}
CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {}
@@ -51,7 +53,7 @@ void CompletionQueue::Shutdown() { grpc_completion_queue_shutdown(cq_); }
CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
void** tag, bool* ok, gpr_timespec deadline) {
for (;;) {
- auto ev = grpc_completion_queue_next(cq_, deadline);
+ auto ev = grpc_completion_queue_next(cq_, deadline, nullptr);
switch (ev.type) {
case GRPC_QUEUE_TIMEOUT:
return TIMEOUT;
@@ -70,8 +72,8 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
}
bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
- auto ev =
- grpc_completion_queue_pluck(cq_, tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+ auto deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+ auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
bool ok = ev.success != 0;
void* ignored = tag;
GPR_ASSERT(tag->FinalizeResult(&ignored, &ok));
@@ -81,8 +83,8 @@ bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
}
void CompletionQueue::TryPluck(CompletionQueueTag* tag) {
- auto ev =
- grpc_completion_queue_pluck(cq_, tag, gpr_time_0(GPR_CLOCK_REALTIME));
+ auto deadline = gpr_time_0(GPR_CLOCK_REALTIME);
+ auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT) return;
bool ok = ev.success != 0;
void* ignored = tag;
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index 63f4a3a0bc..05470ec627 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -154,18 +154,18 @@ class GrpcBufferReader GRPC_FINAL
namespace grpc {
-Status SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) {
+Status SerializeProto(const grpc::protobuf::Message& msg,
+ grpc_byte_buffer** bp) {
GrpcBufferWriter writer(bp);
return msg.SerializeToZeroCopyStream(&writer)
? Status::OK
- : Status(StatusCode::INVALID_ARGUMENT,
- "Failed to serialize message");
+ : Status(StatusCode::INTERNAL, "Failed to serialize message");
}
Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
int max_message_size) {
if (!buffer) {
- return Status(StatusCode::INVALID_ARGUMENT, "No payload");
+ return Status(StatusCode::INTERNAL, "No payload");
}
GrpcBufferReader reader(buffer);
::grpc::protobuf::io::CodedInputStream decoder(&reader);
@@ -173,11 +173,10 @@ Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
decoder.SetTotalBytesLimit(max_message_size, max_message_size);
}
if (!msg->ParseFromCodedStream(&decoder)) {
- return Status(StatusCode::INVALID_ARGUMENT,
- msg->InitializationErrorString());
+ return Status(StatusCode::INTERNAL, msg->InitializationErrorString());
}
if (!decoder.ConsumedEntireMessage()) {
- return Status(StatusCode::INVALID_ARGUMENT, "Did not read entire message");
+ return Status(StatusCode::INTERNAL, "Did not read entire message");
}
return Status::OK;
}
diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc
index 81c84474d8..9f59d254f1 100644
--- a/src/cpp/server/create_default_thread_pool.cc
+++ b/src/cpp/server/create_default_thread_pool.cc
@@ -39,9 +39,9 @@
namespace grpc {
ThreadPoolInterface* CreateDefaultThreadPool() {
- int cores = gpr_cpu_num_cores();
- if (!cores) cores = 4;
- return new DynamicThreadPool(cores);
+ int cores = gpr_cpu_num_cores();
+ if (!cores) cores = 4;
+ return new DynamicThreadPool(cores);
}
} // namespace grpc
diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc
index f58d0420df..b475f43b1d 100644
--- a/src/cpp/server/dynamic_thread_pool.cc
+++ b/src/cpp/server/dynamic_thread_pool.cc
@@ -36,10 +36,10 @@
#include <grpc++/dynamic_thread_pool.h>
namespace grpc {
-DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool *pool):
- pool_(pool),
- thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, this)) {
-}
+DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool* pool)
+ : pool_(pool),
+ thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc,
+ this)) {}
DynamicThreadPool::DynamicThread::~DynamicThread() {
thd_->join();
thd_.reset();
@@ -57,7 +57,7 @@ void DynamicThreadPool::DynamicThread::ThreadFunc() {
pool_->shutdown_cv_.notify_one();
}
}
-
+
void DynamicThreadPool::ThreadFunc() {
for (;;) {
// Wait until work is available or we are shutting down.
@@ -65,7 +65,7 @@ void DynamicThreadPool::ThreadFunc() {
if (!shutdown_ && callbacks_.empty()) {
// If there are too many threads waiting, then quit this thread
if (threads_waiting_ >= reserve_threads_) {
- break;
+ break;
}
threads_waiting_++;
cv_.wait(lock);
@@ -84,9 +84,11 @@ void DynamicThreadPool::ThreadFunc() {
}
}
-DynamicThreadPool::DynamicThreadPool(int reserve_threads) :
- shutdown_(false), reserve_threads_(reserve_threads), nthreads_(0),
- threads_waiting_(0) {
+DynamicThreadPool::DynamicThreadPool(int reserve_threads)
+ : shutdown_(false),
+ reserve_threads_(reserve_threads),
+ nthreads_(0),
+ threads_waiting_(0) {
for (int i = 0; i < reserve_threads_; i++) {
grpc::lock_guard<grpc::mutex> lock(mu_);
nthreads_++;
@@ -96,10 +98,10 @@ DynamicThreadPool::DynamicThreadPool(int reserve_threads) :
void DynamicThreadPool::ReapThreads(std::list<DynamicThread*>* tlist) {
for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) {
- delete *t;
+ delete *t;
}
}
-
+
DynamicThreadPool::~DynamicThreadPool() {
grpc::unique_lock<grpc::mutex> lock(mu_);
shutdown_ = true;
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 32c45e2280..f203cf7f49 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -35,8 +35,8 @@
namespace grpc {
-int SecureServerCredentials::AddPortToServer(
- const grpc::string& addr, grpc_server* server) {
+int SecureServerCredentials::AddPortToServer(const grpc::string& addr,
+ grpc_server* server) {
return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
}
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index ab87b22f5f..e039c07374 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -67,11 +67,17 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
method->method_type() ==
RpcMethod::SERVER_STREAMING),
+ call_details_(nullptr),
cq_(nullptr) {
grpc_metadata_array_init(&request_metadata_);
}
- ~SyncRequest() { grpc_metadata_array_destroy(&request_metadata_); }
+ ~SyncRequest() {
+ if (call_details_) {
+ delete call_details_;
+ }
+ grpc_metadata_array_destroy(&request_metadata_);
+ }
static SyncRequest* Wait(CompletionQueue* cq, bool* ok) {
void* tag = nullptr;
@@ -84,7 +90,27 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
return mrd;
}
- void SetupRequest() { cq_ = grpc_completion_queue_create(); }
+ static bool AsyncWait(CompletionQueue* cq, SyncRequest** req, bool* ok,
+ gpr_timespec deadline) {
+ void* tag = nullptr;
+ *ok = false;
+ switch (cq->AsyncNext(&tag, ok, deadline)) {
+ case CompletionQueue::TIMEOUT:
+ *req = nullptr;
+ return true;
+ case CompletionQueue::SHUTDOWN:
+ *req = nullptr;
+ return false;
+ case CompletionQueue::GOT_EVENT:
+ *req = static_cast<SyncRequest*>(tag);
+ GPR_ASSERT((*req)->in_flight_);
+ return true;
+ }
+ gpr_log(GPR_ERROR, "Should never reach here");
+ abort();
+ }
+
+ void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); }
void TeardownRequest() {
grpc_completion_queue_destroy(cq_);
@@ -94,17 +120,32 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
GPR_ASSERT(cq_ && !in_flight_);
in_flight_ = true;
- GPR_ASSERT(GRPC_CALL_OK ==
- grpc_server_request_registered_call(
- server, tag_, &call_, &deadline_, &request_metadata_,
- has_request_payload_ ? &request_payload_ : nullptr, cq_,
- notify_cq, this));
+ if (tag_) {
+ GPR_ASSERT(GRPC_CALL_OK ==
+ grpc_server_request_registered_call(
+ server, tag_, &call_, &deadline_, &request_metadata_,
+ has_request_payload_ ? &request_payload_ : nullptr, cq_,
+ notify_cq, this));
+ } else {
+ if (!call_details_) {
+ call_details_ = new grpc_call_details;
+ grpc_call_details_init(call_details_);
+ }
+ GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+ server, &call_, call_details_,
+ &request_metadata_, cq_, notify_cq, this));
+ }
}
bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
if (!*status) {
grpc_completion_queue_destroy(cq_);
}
+ if (call_details_) {
+ deadline_ = call_details_->deadline;
+ grpc_call_details_destroy(call_details_);
+ grpc_call_details_init(call_details_);
+ }
return true;
}
@@ -157,6 +198,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
bool in_flight_;
const bool has_request_payload_;
grpc_call* call_;
+ grpc_call_details* call_details_;
gpr_timespec deadline_;
grpc_metadata_array request_metadata_;
grpc_byte_buffer* request_payload_;
@@ -170,9 +212,9 @@ static grpc_server* CreateServer(int max_message_size) {
arg.key = const_cast<char*>(GRPC_ARG_MAX_MESSAGE_LENGTH);
arg.value.integer = max_message_size;
grpc_channel_args args = {1, &arg};
- return grpc_server_create(&args);
+ return grpc_server_create(&args, nullptr);
} else {
- return grpc_server_create(nullptr);
+ return grpc_server_create(nullptr, nullptr);
}
}
@@ -183,10 +225,11 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
shutdown_(false),
num_running_cb_(0),
sync_methods_(new std::list<SyncRequest>),
+ has_generic_service_(false),
server_(CreateServer(max_message_size)),
thread_pool_(thread_pool),
thread_pool_owned_(thread_pool_owned) {
- grpc_server_register_completion_queue(server_, cq_.cq());
+ grpc_server_register_completion_queue(server_, cq_.cq(), nullptr);
}
Server::~Server() {
@@ -207,23 +250,23 @@ Server::~Server() {
delete sync_methods_;
}
-bool Server::RegisterService(const grpc::string *host, RpcService* service) {
+bool Server::RegisterService(const grpc::string* host, RpcService* service) {
for (int i = 0; i < service->GetMethodCount(); ++i) {
RpcServiceMethod* method = service->GetMethod(i);
- void* tag = grpc_server_register_method(
- server_, method->name(), host ? host->c_str() : nullptr);
+ void* tag = grpc_server_register_method(server_, method->name(),
+ host ? host->c_str() : nullptr);
if (!tag) {
gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
method->name());
return false;
}
- SyncRequest request(method, tag);
- sync_methods_->emplace_back(request);
+ sync_methods_->emplace_back(method, tag);
}
return true;
}
-bool Server::RegisterAsyncService(const grpc::string *host, AsynchronousService* service) {
+bool Server::RegisterAsyncService(const grpc::string* host,
+ AsynchronousService* service) {
GPR_ASSERT(service->server_ == nullptr &&
"Can only register an asynchronous service against one server.");
service->server_ = this;
@@ -245,6 +288,7 @@ void Server::RegisterAsyncGenericService(AsyncGenericService* service) {
GPR_ASSERT(service->server_ == nullptr &&
"Can only register an async generic service against one server.");
service->server_ = this;
+ has_generic_service_ = true;
}
int Server::AddListeningPort(const grpc::string& addr,
@@ -258,6 +302,14 @@ bool Server::Start() {
started_ = true;
grpc_server_start(server_);
+ if (!has_generic_service_) {
+ unknown_method_.reset(new RpcServiceMethod(
+ "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler));
+ // Use of emplace_back with just constructor arguments is not accepted here
+ // by gcc-4.4 because it can't match the anonymous nullptr with a proper
+ // constructor implicitly. Construct the object and use push_back.
+ sync_methods_->push_back(SyncRequest(unknown_method_.get(), nullptr));
+ }
// Start processing rpcs.
if (!sync_methods_->empty()) {
for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) {
@@ -271,12 +323,27 @@ bool Server::Start() {
return true;
}
-void Server::Shutdown() {
+void Server::ShutdownInternal(gpr_timespec deadline) {
grpc::unique_lock<grpc::mutex> lock(mu_);
if (started_ && !shutdown_) {
shutdown_ = true;
grpc_server_shutdown_and_notify(server_, cq_.cq(), new ShutdownRequest());
cq_.Shutdown();
+ // Spin, eating requests until the completion queue is completely shutdown.
+ // If the deadline expires then cancel anything that's pending and keep
+ // spinning forever until the work is actually drained.
+ // Since nothing else needs to touch state guarded by mu_, holding it
+ // through this loop is fine.
+ SyncRequest* request;
+ bool ok;
+ while (SyncRequest::AsyncWait(&cq_, &request, &ok, deadline)) {
+ if (request == NULL) { // deadline expired
+ grpc_server_cancel_all_calls(server_);
+ deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ } else if (ok) {
+ SyncRequest::CallData call_data(this, request);
+ }
+ }
// Wait for running callbacks to finish.
while (num_running_cb_ != 0) {
@@ -297,8 +364,8 @@ void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) {
size_t nops = 0;
grpc_op cops[MAX_OPS];
ops->FillOps(cops, &nops);
- GPR_ASSERT(GRPC_CALL_OK ==
- grpc_call_start_batch(call->call(), cops, nops, ops));
+ auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == result);
}
Server::BaseAsyncRequest::BaseAsyncRequest(
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index f723d4611a..0b11d86173 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -38,6 +38,7 @@
#include <grpc++/impl/service_type.h>
#include <grpc++/server.h>
#include <grpc++/thread_pool_interface.h>
+#include <grpc++/fixed_size_thread_pool.h>
namespace grpc {
@@ -58,14 +59,16 @@ void ServerBuilder::RegisterAsyncService(AsynchronousService* service) {
async_services_.emplace_back(new NamedService<AsynchronousService>(service));
}
-void ServerBuilder::RegisterService(
- const grpc::string& addr, SynchronousService* service) {
- services_.emplace_back(new NamedService<RpcService>(addr, service->service()));
+void ServerBuilder::RegisterService(const grpc::string& addr,
+ SynchronousService* service) {
+ services_.emplace_back(
+ new NamedService<RpcService>(addr, service->service()));
}
-void ServerBuilder::RegisterAsyncService(
- const grpc::string& addr, AsynchronousService* service) {
- async_services_.emplace_back(new NamedService<AsynchronousService>(addr, service));
+void ServerBuilder::RegisterAsyncService(const grpc::string& addr,
+ AsynchronousService* service) {
+ async_services_.emplace_back(
+ new NamedService<AsynchronousService>(addr, service));
}
void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
@@ -100,10 +103,17 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
thread_pool_ = CreateDefaultThreadPool();
thread_pool_owned = true;
}
+ // Async services only, create a thread pool to handle requests to unknown
+ // services.
+ if (!thread_pool_ && !generic_service_ && !async_services_.empty()) {
+ thread_pool_ = new FixedSizeThreadPool(1);
+ thread_pool_owned = true;
+ }
std::unique_ptr<Server> server(
new Server(thread_pool_, thread_pool_owned, max_message_size_));
for (auto cq = cqs_.begin(); cq != cqs_.end(); ++cq) {
- grpc_server_register_completion_queue(server->server_, (*cq)->cq());
+ grpc_server_register_completion_queue(server->server_, (*cq)->cq(),
+ nullptr);
}
for (auto service = services_.begin(); service != services_.end();
service++) {
@@ -111,9 +121,10 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
return nullptr;
}
}
- for (auto service = async_services_.begin();
- service != async_services_.end(); service++) {
- if (!server->RegisterAsyncService((*service)->host.get(), (*service)->service)) {
+ for (auto service = async_services_.begin(); service != async_services_.end();
+ service++) {
+ if (!server->RegisterAsyncService((*service)->host.get(),
+ (*service)->service)) {
return nullptr;
}
}
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 04373397f9..03461ddda5 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -50,7 +50,12 @@ namespace grpc {
class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface {
public:
// initial refs: one in the server context, one in the cq
- CompletionOp() : has_tag_(false), tag_(nullptr), refs_(2), finalized_(false), cancelled_(0) {}
+ CompletionOp()
+ : has_tag_(false),
+ tag_(nullptr),
+ refs_(2),
+ finalized_(false),
+ cancelled_(0) {}
void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE;
bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
@@ -91,6 +96,7 @@ void ServerContext::CompletionOp::FillOps(grpc_op* ops, size_t* nops) {
ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
ops->data.recv_close_on_server.cancelled = &cancelled_;
ops->flags = 0;
+ ops->reserved = NULL;
*nops = 1;
}
diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs
new file mode 100644
index 0000000000..61338f7f0e
--- /dev/null
+++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs
@@ -0,0 +1,84 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading;
+
+using Google.Apis.Auth.OAuth2;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+ /// <summary>
+ /// Factory methods to create authorization interceptors.
+ /// </summary>
+ public static class AuthInterceptors
+ {
+ private const string AuthorizationHeader = "Authorization";
+ private const string Schema = "Bearer";
+
+ /// <summary>
+ /// Creates interceptor that will obtain access token from any credential type that implements
+ /// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
+ /// </summary>
+ public static HeaderInterceptor FromCredential(ITokenAccess credential)
+ {
+ return new HeaderInterceptor((method, authUri, metadata) =>
+ {
+ // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+ var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
+ .ConfigureAwait(false).GetAwaiter().GetResult();
+ metadata.Add(CreateBearerTokenHeader(accessToken));
+ });
+ }
+
+ /// <summary>
+ /// Creates OAuth2 interceptor that will use given access token as authorization.
+ /// </summary>
+ /// <param name="accessToken">OAuth2 access token.</param>
+ public static HeaderInterceptor FromAccessToken(string accessToken)
+ {
+ Preconditions.CheckNotNull(accessToken);
+ return new HeaderInterceptor((method, authUri, metadata) =>
+ {
+ metadata.Add(CreateBearerTokenHeader(accessToken));
+ });
+ }
+
+ private static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+ {
+ return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 930a34b0c3..4fb087d4a3 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -3,8 +3,6 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Grpc.Auth</RootNamespace>
@@ -41,57 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
+ <Reference Include="BouncyCastle.Crypto">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Apis.Auth">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Apis.Auth.PlatformServices">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Google.Apis.Core">
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
- <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Net" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System.Net.Http.Extensions">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
</Reference>
- <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System.Net.Http.Primitives">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
</Reference>
- <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="OAuth2Interceptors.cs" />
+ <Compile Include="AuthInterceptors.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index 2dc10d24c2..f1f8f7c709 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,7 +15,7 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
<dependencies>
- <dependency id="Google.Apis.Auth" version="1.9.2" />
+ <dependency id="Google.Apis.Auth" version="1.9.3" />
<dependency id="Grpc.Core" version="$version$" />
</dependencies>
</metadata>
diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
deleted file mode 100644
index d628a83246..0000000000
--- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Security.Cryptography.X509Certificates;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Google.Apis.Auth.OAuth2;
-using Google.Apis.Util;
-using Grpc.Core;
-using Grpc.Core.Utils;
-
-namespace Grpc.Auth
-{
- public static class OAuth2Interceptors
- {
- /// <summary>
- /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
- /// </summary>
- public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
- {
- var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default);
- return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
- }
-
- /// <summary>
- /// Creates OAuth2 interceptor that will use given OAuth2 token.
- /// </summary>
- /// <param name="oauth2Token"></param>
- /// <returns></returns>
- public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
- {
- Preconditions.CheckNotNull(oauth2Token);
- return new MetadataInterceptorDelegate((authUri, metadata) =>
- {
- metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
- });
- }
-
- /// <summary>
- /// Injects OAuth2 authorization header into initial metadata (= request headers).
- /// </summary>
- private class OAuth2Interceptor
- {
- private const string AuthorizationHeader = "Authorization";
- private const string Schema = "Bearer";
-
- private ITokenAccess credential;
- private IClock clock;
-
- public OAuth2Interceptor(ITokenAccess credential, IClock clock)
- {
- this.credential = credential;
- this.clock = clock;
- }
-
- /// <summary>
- /// Gets access token and requests refreshing it if is going to expire soon.
- /// </summary>
- /// <param name="cancellationToken"></param>
- /// <returns></returns>
- public string GetAccessToken(string authUri, CancellationToken cancellationToken)
- {
- // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
- return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult();
- }
-
- public void InterceptHeaders(string authUri, Metadata metadata)
- {
- var accessToken = GetAccessToken(authUri, CancellationToken.None);
- metadata.Add(CreateBearerTokenHeader(accessToken));
- }
-
- public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
- {
- return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
- }
- }
- }
-}
diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
index bf020cd627..fb9b562c77 100644
--- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
@@ -89,6 +89,24 @@ namespace Grpc.Core
}
/// <summary>
+ /// Gets the call status if the call has already finished.
+ /// Throws InvalidOperationException otherwise.
+ /// </summary>
+ public Status GetStatus()
+ {
+ return getStatusFunc();
+ }
+
+ /// <summary>
+ /// Gets the call trailing metadata if the call has already finished.
+ /// Throws InvalidOperationException otherwise.
+ /// </summary>
+ public Metadata GetTrailers()
+ {
+ return getTrailersFunc();
+ }
+
+ /// <summary>
/// Provides means to cleanup after the call.
/// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything.
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
index 0979de606f..183c84216a 100644
--- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
@@ -32,8 +32,6 @@
#endregion
using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
namespace Grpc.Core
{
diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
index 380efcdb0e..ab2049f269 100644
--- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
@@ -32,8 +32,6 @@
#endregion
using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
namespace Grpc.Core
{
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 0cb2953f2c..ad54b46ad5 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -71,7 +71,7 @@ namespace Grpc.Core
/// Creates a channel option with an integer value.
/// </summary>
/// <param name="name">Name.</param>
- /// <param name="stringValue">String value.</param>
+ /// <param name="intValue">Integer value.</param>
public ChannelOption(string name, int intValue)
{
this.type = OptionType.Integer;
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f240d777b9..7bc100ca60 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -32,15 +32,15 @@
#endregion
using System;
-using System.Collections.Generic;
using System.Text.RegularExpressions;
-
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+using System.Threading.Tasks;
namespace Grpc.Core
{
- public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata);
+ /// <summary>
+ /// Interceptor for call headers.
+ /// </summary>
+ public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
/// <summary>
/// Base class for client-side stubs.
@@ -60,10 +60,10 @@ namespace Grpc.Core
}
/// <summary>
- /// Can be used to register a custom header (initial metadata) interceptor.
- /// The delegate each time before a new call on this client is started.
+ /// Can be used to register a custom header (request metadata) interceptor.
+ /// The interceptor is invoked each time a new call on this client is started.
/// </summary>
- public MetadataInterceptorDelegate HeaderInterceptor
+ public HeaderInterceptor HeaderInterceptor
{
get;
set;
@@ -107,7 +107,7 @@ namespace Grpc.Core
options = options.WithHeaders(new Metadata());
}
var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
- interceptor(authUri, options.Headers);
+ interceptor(method, authUri, options.Headers);
}
return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 4c208b4a26..4c53285893 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -55,9 +55,36 @@ namespace Grpc.Core
}
/// <summary>
+ /// A non-generic representation of a remote method.
+ /// </summary>
+ public interface IMethod
+ {
+ /// <summary>
+ /// Gets the type of the method.
+ /// </summary>
+ MethodType Type { get; }
+
+ /// <summary>
+ /// Gets the name of the service to which this method belongs.
+ /// </summary>
+ string ServiceName { get; }
+
+ /// <summary>
+ /// Gets the unqualified name of the method.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the fully qualified name of the method. On the server side, methods are dispatched
+ /// based on this name.
+ /// </summary>
+ string FullName { get; }
+ }
+
+ /// <summary>
/// A description of a remote method.
/// </summary>
- public class Method<TRequest, TResponse>
+ public class Method<TRequest, TResponse> : IMethod
{
readonly MethodType type;
readonly string serviceName;
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 385ca92086..f4b0a1028f 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -308,7 +308,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("running service_account_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
credential = credential.CreateScoped(new[] { AuthScope });
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -332,7 +332,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("running compute_engine_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -357,7 +357,7 @@ namespace Grpc.IntegrationTesting
var credential = await GoogleCredential.GetApplicationDefaultAsync();
// check this a credential with scope support, but don't add the scope.
Assert.IsTrue(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -381,7 +381,7 @@ namespace Grpc.IntegrationTesting
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+ client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
@@ -401,7 +401,7 @@ namespace Grpc.IntegrationTesting
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+ var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
@@ -409,7 +409,7 @@ namespace Grpc.IntegrationTesting
.Build();
var headers = new Metadata();
- headerInterceptor("", headers);
+ headerInterceptor(null, "", headers);
var response = client.UnaryCall(request, headers: headers);
Assert.AreEqual(AuthScopeResponse, response.OauthScope);
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 9379ae01f1..fc9470f93f 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -339,7 +339,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_shutdown(void) { grpc_shutdown(); }
GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE
grpcsharp_completion_queue_create(void) {
- return grpc_completion_queue_create();
+ return grpc_completion_queue_create(NULL);
}
GPR_EXPORT void GPR_CALLTYPE
@@ -354,13 +354,14 @@ grpcsharp_completion_queue_destroy(grpc_completion_queue *cq) {
GPR_EXPORT grpc_event GPR_CALLTYPE
grpcsharp_completion_queue_next(grpc_completion_queue *cq) {
- return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
+ return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
+ NULL);
}
GPR_EXPORT grpc_event GPR_CALLTYPE
grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
return grpc_completion_queue_pluck(cq, tag,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
/* Channel */
@@ -368,7 +369,7 @@ grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
GPR_EXPORT grpc_channel *GPR_CALLTYPE
grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) {
- return grpc_insecure_channel_create(target, args);
+ return grpc_insecure_channel_create(target, args, NULL);
}
GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
@@ -382,7 +383,7 @@ grpcsharp_channel_create_call(grpc_channel *channel, grpc_call *parent_call,
const char *method, const char *host,
gpr_timespec deadline) {
return grpc_channel_create_call(channel, parent_call, propagation_mask, cq,
- method, host, deadline);
+ method, host, deadline, NULL);
}
GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE
@@ -475,13 +476,13 @@ GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
/* Call */
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call *call) {
- return grpc_call_cancel(call);
+ return grpc_call_cancel(call, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status,
const char *description) {
- return grpc_call_cancel_with_status(call, status, description);
+ return grpc_call_cancel_with_status(call, status, description, NULL);
}
GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) {
@@ -509,22 +510,27 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
ops[1].data.send_message = ctx->send_message;
ops[1].flags = write_flags;
+ ops[1].reserved = NULL;
ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
ops[2].flags = 0;
+ ops[2].reserved = NULL;
ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[3].flags = 0;
+ ops[3].reserved = NULL;
ops[4].op = GRPC_OP_RECV_MESSAGE;
ops[4].data.recv_message = &(ctx->recv_message);
ops[4].flags = 0;
+ ops[4].reserved = NULL;
ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
ops[5].data.recv_status_on_client.trailing_metadata =
@@ -537,8 +543,10 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
ops[5].data.recv_status_on_client.status_details_capacity =
&(ctx->recv_status_on_client.status_details_capacity);
ops[5].flags = 0;
+ ops[5].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -554,14 +562,17 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[1].flags = 0;
+ ops[1].reserved = NULL;
ops[2].op = GRPC_OP_RECV_MESSAGE;
ops[2].data.recv_message = &(ctx->recv_message);
ops[2].flags = 0;
+ ops[2].reserved = NULL;
ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
ops[3].data.recv_status_on_client.trailing_metadata =
@@ -574,8 +585,10 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
ops[3].data.recv_status_on_client.status_details_capacity =
&(ctx->recv_status_on_client.status_details_capacity);
ops[3].flags = 0;
+ ops[3].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
@@ -590,18 +603,22 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
ops[1].data.send_message = ctx->send_message;
ops[1].flags = write_flags;
+ ops[1].reserved = NULL;
ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
ops[2].flags = 0;
+ ops[2].reserved = NULL;
ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[3].flags = 0;
+ ops[3].reserved = NULL;
ops[4].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
ops[4].data.recv_status_on_client.trailing_metadata =
@@ -614,8 +631,10 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
ops[4].data.recv_status_on_client.status_details_capacity =
&(ctx->recv_status_on_client.status_details_capacity);
ops[4].flags = 0;
+ ops[4].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -631,10 +650,12 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[1].flags = 0;
+ ops[1].reserved = NULL;
ops[2].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
ops[2].data.recv_status_on_client.trailing_metadata =
@@ -647,8 +668,10 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
ops[2].data.recv_status_on_client.status_details_capacity =
&(ctx->recv_status_on_client.status_details_capacity);
ops[2].flags = 0;
+ ops[2].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -663,12 +686,14 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx,
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
ops[0].data.send_message = ctx->send_message;
ops[0].flags = write_flags;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
ops[1].data.send_initial_metadata.count = 0;
ops[1].data.send_initial_metadata.metadata = NULL;
ops[1].flags = 0;
+ ops[1].reserved = NULL;
- return grpc_call_start_batch(call, ops, nops, ctx);
+ return grpc_call_start_batch(call, ops, nops, ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -678,8 +703,10 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
grpc_op ops[1];
ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
@@ -700,12 +727,14 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
ops[0].data.send_status_from_server.trailing_metadata =
ctx->send_status_from_server.trailing_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
ops[1].data.send_initial_metadata.count = 0;
ops[1].data.send_initial_metadata.metadata = NULL;
ops[1].flags = 0;
+ ops[1].reserved = NULL;
- return grpc_call_start_batch(call, ops, nops, ctx);
+ return grpc_call_start_batch(call, ops, nops, ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -715,7 +744,9 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) {
ops[0].op = GRPC_OP_RECV_MESSAGE;
ops[0].data.recv_message = &(ctx->recv_message);
ops[0].flags = 0;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ ops[0].reserved = NULL;
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -726,8 +757,10 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) {
ops[0].data.recv_close_on_server.cancelled =
(&ctx->recv_close_on_server_cancelled);
ops[0].flags = 0;
+ ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -743,8 +776,10 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
+ ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
/* Server */
@@ -752,8 +787,8 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
GPR_EXPORT grpc_server *GPR_CALLTYPE
grpcsharp_server_create(grpc_completion_queue *cq,
const grpc_channel_args *args) {
- grpc_server *server = grpc_server_create(args);
- grpc_server_register_completion_queue(server, cq);
+ grpc_server *server = grpc_server_create(args, NULL);
+ grpc_server_register_completion_queue(server, cq, NULL);
return server;
}
diff --git a/src/node/README.md b/src/node/README.md
index 7d3d8c7fa1..b6411537c7 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -5,11 +5,35 @@ Alpha : Ready for early adopters
## PREREQUISITES
- `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core.
## INSTALLATION
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Node.js.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC NPM package
+
+```sh
+npm install grpc
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Node.js.
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs
```
@@ -88,5 +112,5 @@ ServerCredentials
An object with factory methods for creating credential objects for servers.
[homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/node/examples/perf_test.js b/src/node/examples/perf_test.js
index 214b9384d5..ba8fbf88d2 100644
--- a/src/node/examples/perf_test.js
+++ b/src/node/examples/perf_test.js
@@ -40,7 +40,7 @@ var interop_server = require('../interop/interop_server.js');
function runTest(iterations, callback) {
var testServer = interop_server.getServer(0, false);
- testServer.server.listen();
+ testServer.server.start();
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
diff --git a/src/node/examples/qps_test.js b/src/node/examples/qps_test.js
index 1ce4dbe070..ec968b8540 100644
--- a/src/node/examples/qps_test.js
+++ b/src/node/examples/qps_test.js
@@ -60,7 +60,7 @@ var interop_server = require('../interop/interop_server.js');
*/
function runTest(concurrent_calls, seconds, callback) {
var testServer = interop_server.getServer(0, false);
- testServer.server.listen();
+ testServer.server.start();
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js
index bb8e79b5bd..465b32f54f 100644
--- a/src/node/examples/route_guide_server.js
+++ b/src/node/examples/route_guide_server.js
@@ -248,7 +248,7 @@ if (require.main === module) {
throw err;
}
feature_list = JSON.parse(data);
- routeServer.listen();
+ routeServer.start();
});
}
diff --git a/src/node/examples/stock_server.js b/src/node/examples/stock_server.js
index dfcfe30eb4..12e5479584 100644
--- a/src/node/examples/stock_server.js
+++ b/src/node/examples/stock_server.js
@@ -81,7 +81,7 @@ stockServer.addProtoService(examples.Stock.service, {
if (require.main === module) {
stockServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
- stockServer.listen();
+ stockServer.start();
}
module.exports = stockServer;
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index c5c8313385..18858fa334 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -207,6 +207,13 @@ class SendMessageOp : public Op {
if (!::node::Buffer::HasInstance(value)) {
return false;
}
+ Handle<Object> object_value = value->ToObject();
+ if (object_value->HasOwnProperty(NanNew("grpcWriteFlags"))) {
+ Handle<Value> flag_value = object_value->Get(NanNew("grpcWriteFlags"));
+ if (flag_value->IsUint32()) {
+ out->flags = flag_value->Uint32Value() & GRPC_WRITE_USED_MASK;
+ }
+ }
out->data.send_message = BufferToByteBuffer(value);
Persistent<Value> *handle = new Persistent<Value>();
NanAssignPersistent(*handle, value);
@@ -457,10 +464,6 @@ void Call::Init(Handle<Object> exports) {
NanNew<FunctionTemplate>(GetPeer)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
Handle<Function> ctr = tpl->GetFunction();
- ctr->Set(NanNew("WRITE_BUFFER_HINT"),
- NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
- ctr->Set(NanNew("WRITE_NO_COMPRESS"),
- NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
exports->Set(NanNew("Call"), ctr);
constructor = new NanCallback(ctr);
}
@@ -502,6 +505,22 @@ NAN_METHOD(Call::New) {
return NanThrowTypeError(
"Call's third argument must be a date or a number");
}
+ // These arguments are at the end because they are optional
+ grpc_call *parent_call = NULL;
+ if (Call::HasInstance(args[4])) {
+ Call *parent_obj = ObjectWrap::Unwrap<Call>(args[4]->ToObject());
+ parent_call = parent_obj->wrapped_call;
+ } else if (!(args[4]->IsUndefined() || args[4]->IsNull())) {
+ return NanThrowTypeError(
+ "Call's fifth argument must be another call, if provided");
+ }
+ gpr_uint32 propagate_flags = GRPC_PROPAGATE_DEFAULTS;
+ if (args[5]->IsUint32()) {
+ propagate_flags = args[5]->Uint32Value();
+ } else if (!(args[5]->IsUndefined() || args[5]->IsNull())) {
+ return NanThrowTypeError(
+ "Call's sixth argument must be propagate flags, if provided");
+ }
Handle<Object> channel_object = args[0]->ToObject();
Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
if (channel->GetWrappedChannel() == NULL) {
@@ -514,14 +533,14 @@ NAN_METHOD(Call::New) {
if (args[3]->IsString()) {
NanUtf8String host_override(args[3]);
wrapped_call = grpc_channel_create_call(
- wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+ wrapped_channel, parent_call, propagate_flags,
CompletionQueueAsyncWorker::GetQueue(), *method,
- *host_override, MillisecondsToTimespec(deadline));
+ *host_override, MillisecondsToTimespec(deadline), NULL);
} else if (args[3]->IsUndefined() || args[3]->IsNull()) {
wrapped_call = grpc_channel_create_call(
- wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+ wrapped_channel, parent_call, propagate_flags,
CompletionQueueAsyncWorker::GetQueue(), *method,
- NULL, MillisecondsToTimespec(deadline));
+ NULL, MillisecondsToTimespec(deadline), NULL);
} else {
return NanThrowTypeError("Call's fourth argument must be a string");
}
@@ -565,6 +584,7 @@ NAN_METHOD(Call::StartBatch) {
uint32_t type = keys->Get(i)->Uint32Value();
ops[i].op = static_cast<grpc_op_type>(type);
ops[i].flags = 0;
+ ops[i].reserved = NULL;
switch (type) {
case GRPC_OP_SEND_INITIAL_METADATA:
op.reset(new SendMetadataOp());
@@ -601,9 +621,9 @@ NAN_METHOD(Call::StartBatch) {
NanCallback *callback = new NanCallback(callback_func);
grpc_call_error error = grpc_call_start_batch(
call->wrapped_call, &ops[0], nops, new struct tag(
- callback, op_vector.release(), resources));
+ callback, op_vector.release(), resources), NULL);
if (error != GRPC_CALL_OK) {
- return NanThrowError("startBatch failed", error);
+ return NanThrowError(nanErrorWithCode("startBatch failed", error));
}
CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
@@ -615,9 +635,9 @@ NAN_METHOD(Call::Cancel) {
return NanThrowTypeError("cancel can only be called on Call objects");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_cancel(call->wrapped_call);
+ grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL);
if (error != GRPC_CALL_OK) {
- return NanThrowError("cancel failed", error);
+ return NanThrowError(nanErrorWithCode("cancel failed", error));
}
NanReturnUndefined();
}
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 6acda76197..ef6e5fcd21 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -51,6 +51,19 @@ namespace node {
using std::unique_ptr;
using std::shared_ptr;
+/**
+ * Helper function for throwing errors with a grpc_call_error value.
+ * Modified from the answer by Gus Goose to
+ * http://stackoverflow.com/questions/31794200.
+ */
+inline v8::Local<v8::Value> nanErrorWithCode(const char *msg,
+ grpc_call_error code) {
+ NanEscapableScope();
+ v8::Local<v8::Object> err = NanError(msg).As<v8::Object>();
+ err->Set(NanNew("code"), NanNew<v8::Uint32>(code));
+ return NanEscapeScope(err);
+}
+
v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array);
class PersistentHolder {
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 457a58c057..a61c830099 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -33,12 +33,17 @@
#include <vector>
+#include "grpc/support/log.h"
+
#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
+#include "call.h"
#include "channel.h"
+#include "completion_queue_async_worker.h"
#include "credentials.h"
+#include "timeval.h"
namespace grpc {
namespace node {
@@ -51,6 +56,7 @@ using v8::Handle;
using v8::HandleScope;
using v8::Integer;
using v8::Local;
+using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
@@ -76,6 +82,12 @@ void Channel::Init(Handle<Object> exports) {
NanNew<FunctionTemplate>(Close)->GetFunction());
NanSetPrototypeTemplate(tpl, "getTarget",
NanNew<FunctionTemplate>(GetTarget)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "getConnectivityState",
+ NanNew<FunctionTemplate>(GetConnectivityState)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "watchConnectivityState",
+ NanNew<FunctionTemplate>(WatchConnectivityState)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
Handle<Function> ctr = tpl->GetFunction();
constructor = new NanCallback(ctr);
@@ -111,7 +123,7 @@ NAN_METHOD(Channel::New) {
grpc_channel_args *channel_args_ptr;
if (args[2]->IsUndefined()) {
channel_args_ptr = NULL;
- wrapped_channel = grpc_insecure_channel_create(*host, NULL);
+ wrapped_channel = grpc_insecure_channel_create(*host, NULL, NULL);
} else if (args[2]->IsObject()) {
Handle<Object> args_hash(args[2]->ToObject()->Clone());
Handle<Array> keys(args_hash->GetOwnPropertyNames());
@@ -145,7 +157,8 @@ NAN_METHOD(Channel::New) {
return NanThrowTypeError("Channel expects a string and an object");
}
if (creds == NULL) {
- wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr);
+ wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr,
+ NULL);
} else {
wrapped_channel =
grpc_secure_channel_create(creds, *host, channel_args_ptr);
@@ -185,5 +198,52 @@ NAN_METHOD(Channel::GetTarget) {
NanReturnValue(NanNew(grpc_channel_get_target(channel->wrapped_channel)));
}
+NAN_METHOD(Channel::GetConnectivityState) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "getConnectivityState can only be called on Channel objects");
+ }
+ Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+ int try_to_connect = (int)args[0]->Equals(NanTrue());
+ NanReturnValue(grpc_channel_check_connectivity_state(channel->wrapped_channel,
+ try_to_connect));
+}
+
+NAN_METHOD(Channel::WatchConnectivityState) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "watchConnectivityState can only be called on Channel objects");
+ }
+ if (!args[0]->IsUint32()) {
+ return NanThrowTypeError(
+ "watchConnectivityState's first argument must be a channel state");
+ }
+ if (!(args[1]->IsNumber() || args[1]->IsDate())) {
+ return NanThrowTypeError(
+ "watchConnectivityState's second argument must be a date or a number");
+ }
+ if (!args[2]->IsFunction()) {
+ return NanThrowTypeError(
+ "watchConnectivityState's third argument must be a callback");
+ }
+ grpc_connectivity_state last_state =
+ static_cast<grpc_connectivity_state>(args[0]->Uint32Value());
+ double deadline = args[1]->NumberValue();
+ Handle<Function> callback_func = args[2].As<Function>();
+ NanCallback *callback = new NanCallback(callback_func);
+ Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+ unique_ptr<OpVec> ops(new OpVec());
+ grpc_channel_watch_connectivity_state(
+ channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline),
+ CompletionQueueAsyncWorker::GetQueue(),
+ new struct tag(callback,
+ ops.release(),
+ shared_ptr<Resources>(nullptr)));
+ CompletionQueueAsyncWorker::Next();
+ NanReturnUndefined();
+}
+
} // namespace node
} // namespace grpc
diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h
index e2182cb45c..458f71d093 100644
--- a/src/node/ext/channel.h
+++ b/src/node/ext/channel.h
@@ -64,6 +64,8 @@ class Channel : public ::node::ObjectWrap {
static NAN_METHOD(New);
static NAN_METHOD(Close);
static NAN_METHOD(GetTarget);
+ static NAN_METHOD(GetConnectivityState);
+ static NAN_METHOD(WatchConnectivityState);
static NanCallback *constructor;
static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index 1215c97e19..bf2cd946a5 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -63,9 +63,9 @@ CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
void CompletionQueueAsyncWorker::Execute() {
result =
- grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME));
+ grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
if (!result.success) {
- SetErrorMessage("The batch encountered an error");
+ SetErrorMessage("The async function encountered an error");
}
}
@@ -85,7 +85,7 @@ void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
NanScope();
current_threads = 0;
waiting_next_calls = 0;
- queue = grpc_completion_queue_create();
+ queue = grpc_completion_queue_create(NULL);
}
void CompletionQueueAsyncWorker::HandleOKCallback() {
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index 4e31cbaa27..0cf30da922 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -159,12 +159,62 @@ void InitOpTypeConstants(Handle<Object> exports) {
op_type->Set(NanNew("RECV_CLOSE_ON_SERVER"), RECV_CLOSE_ON_SERVER);
}
+void InitPropagateConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> propagate = NanNew<Object>();
+ exports->Set(NanNew("propagate"), propagate);
+ Handle<Value> DEADLINE(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEADLINE));
+ propagate->Set(NanNew("DEADLINE"), DEADLINE);
+ Handle<Value> CENSUS_STATS_CONTEXT(
+ NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT));
+ propagate->Set(NanNew("CENSUS_STATS_CONTEXT"), CENSUS_STATS_CONTEXT);
+ Handle<Value> CENSUS_TRACING_CONTEXT(
+ NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT));
+ propagate->Set(NanNew("CENSUS_TRACING_CONTEXT"), CENSUS_TRACING_CONTEXT);
+ Handle<Value> CANCELLATION(
+ NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CANCELLATION));
+ propagate->Set(NanNew("CANCELLATION"), CANCELLATION);
+ Handle<Value> DEFAULTS(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEFAULTS));
+ propagate->Set(NanNew("DEFAULTS"), DEFAULTS);
+}
+
+void InitConnectivityStateConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> channel_state = NanNew<Object>();
+ exports->Set(NanNew("connectivityState"), channel_state);
+ Handle<Value> IDLE(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_IDLE));
+ channel_state->Set(NanNew("IDLE"), IDLE);
+ Handle<Value> CONNECTING(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_CONNECTING));
+ channel_state->Set(NanNew("CONNECTING"), CONNECTING);
+ Handle<Value> READY(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_READY));
+ channel_state->Set(NanNew("READY"), READY);
+ Handle<Value> TRANSIENT_FAILURE(
+ NanNew<Uint32, uint32_t>(GRPC_CHANNEL_TRANSIENT_FAILURE));
+ channel_state->Set(NanNew("TRANSIENT_FAILURE"), TRANSIENT_FAILURE);
+ Handle<Value> FATAL_FAILURE(
+ NanNew<Uint32, uint32_t>(GRPC_CHANNEL_FATAL_FAILURE));
+ channel_state->Set(NanNew("FATAL_FAILURE"), FATAL_FAILURE);
+}
+
+void InitWriteFlags(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> write_flags = NanNew<Object>();
+ exports->Set(NanNew("writeFlags"), write_flags);
+ Handle<Value> BUFFER_HINT(NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
+ write_flags->Set(NanNew("BUFFER_HINT"), BUFFER_HINT);
+ Handle<Value> NO_COMPRESS(NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
+ write_flags->Set(NanNew("NO_COMPRESS"), NO_COMPRESS);
+}
+
void init(Handle<Object> exports) {
NanScope();
grpc_init();
InitStatusConstants(exports);
InitCallErrorConstants(exports);
InitOpTypeConstants(exports);
+ InitPropagateConstants(exports);
+ InitConnectivityStateConstants(exports);
+ InitWriteFlags(exports);
grpc::node::Call::Init(exports);
grpc::node::Channel::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 1dc179db3d..01217bce79 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -113,8 +113,8 @@ class NewCallOp : public Op {
};
Server::Server(grpc_server *server) : wrapped_server(server) {
- shutdown_queue = grpc_completion_queue_create();
- grpc_server_register_completion_queue(server, shutdown_queue);
+ shutdown_queue = grpc_completion_queue_create(NULL);
+ grpc_server_register_completion_queue(server, shutdown_queue, NULL);
}
Server::~Server() {
@@ -158,7 +158,7 @@ void Server::ShutdownServer() {
this->shutdown_queue,
NULL);
grpc_completion_queue_pluck(this->shutdown_queue, NULL,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
this->wrapped_server = NULL;
}
}
@@ -176,7 +176,7 @@ NAN_METHOD(Server::New) {
grpc_server *wrapped_server;
grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue();
if (args[0]->IsUndefined()) {
- wrapped_server = grpc_server_create(NULL);
+ wrapped_server = grpc_server_create(NULL, NULL);
} else if (args[0]->IsObject()) {
Handle<Object> args_hash(args[0]->ToObject());
Handle<Array> keys(args_hash->GetOwnPropertyNames());
@@ -205,12 +205,12 @@ NAN_METHOD(Server::New) {
return NanThrowTypeError("Arg values must be strings");
}
}
- wrapped_server = grpc_server_create(&channel_args);
+ wrapped_server = grpc_server_create(&channel_args, NULL);
free(channel_args.args);
} else {
return NanThrowTypeError("Server expects an object");
}
- grpc_server_register_completion_queue(wrapped_server, queue);
+ grpc_server_register_completion_queue(wrapped_server, queue, NULL);
Server *server = new Server(wrapped_server);
server->Wrap(args.This());
NanReturnValue(args.This());
@@ -235,7 +235,7 @@ NAN_METHOD(Server::RequestCall) {
new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
shared_ptr<Resources>(nullptr)));
if (error != GRPC_CALL_OK) {
- return NanThrowError("requestCall failed", error);
+ return NanThrowError(nanErrorWithCode("requestCall failed", error));
}
CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
diff --git a/src/node/index.js b/src/node/index.js
index b26ab35f2c..889b0ac0e9 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -135,11 +135,21 @@ exports.Server = server.Server;
exports.status = grpc.status;
/**
+ * Propagate flag name to number mapping
+ */
+exports.propagate = grpc.propagate;
+
+/**
* Call error name to code number mapping
*/
exports.callError = grpc.callError;
/**
+ * Write flag name to code number mapping
+ */
+exports.writeFlags = grpc.writeFlags;
+
+/**
* Credentials factories
*/
exports.Credentials = grpc.Credentials;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 6d6f9a349e..612dcf01f6 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -264,7 +264,9 @@ function timeoutOnSleepingServer(client, done) {
payload: {body: zeroBuffer(27182)}
});
call.on('error', function(error) {
- assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED);
+
+ assert(error.code === grpc.status.DEADLINE_EXCEEDED ||
+ error.code === grpc.status.INTERNAL);
done();
});
}
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index ece22cce31..1242a0f939 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -194,7 +194,7 @@ if (require.main === module) {
});
var server_obj = getServer(argv.port, argv.use_tls === 'true');
console.log('Server attaching to port ' + argv.port);
- server_obj.server.listen();
+ server_obj.server.start();
}
/**
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 5cde438572..48fe0dd3b7 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -79,13 +79,19 @@ function ClientWritableStream(call, serialize) {
* implementation of a method needed for implementing stream.Writable.
* @access private
* @param {Buffer} chunk The chunk to write
- * @param {string} encoding Ignored
+ * @param {string} encoding Used to pass write flags
* @param {function(Error=)} callback Called when the write is complete
*/
function _write(chunk, encoding, callback) {
/* jshint validthis: true */
var batch = {};
- batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ var message = this.serialize(chunk);
+ if (_.isFinite(encoding)) {
+ /* Attach the encoding if it is a finite number. This is the closest we
+ * can get to checking that it is valid flags */
+ message.grpcWriteFlags = encoding;
+ }
+ batch[grpc.opType.SEND_MESSAGE] = message;
this.call.startBatch(batch, function(err, event) {
if (err) {
// Something has gone wrong. Stop writing by failing to call callback
@@ -216,14 +222,19 @@ ClientDuplexStream.prototype.getPeer = getPeer;
function getCall(channel, method, options) {
var deadline;
var host;
+ var parent;
+ var propagate_flags;
if (options) {
deadline = options.deadline;
host = options.host;
+ parent = _.get(options, 'parent.call');
+ propagate_flags = options.propagate_flags;
}
if (deadline === undefined) {
deadline = Infinity;
}
- return new grpc.Call(channel, method, deadline, host);
+ return new grpc.Call(channel, method, deadline, host,
+ parent, propagate_flags);
}
/**
@@ -268,8 +279,10 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
return;
}
var client_batch = {};
+ var message = serialize(argument);
+ message.grpcWriteFlags = options.flags;
client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
- client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ client_batch[grpc.opType.SEND_MESSAGE] = message;
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
client_batch[grpc.opType.RECV_MESSAGE] = true;
@@ -402,9 +415,11 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
return;
}
var start_batch = {};
+ var message = serialize(argument);
+ message.grpcWriteFlags = options.flags;
start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
- start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ start_batch[grpc.opType.SEND_MESSAGE] = message;
start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
call.startBatch(start_batch, function(err, response) {
if (err) {
@@ -558,6 +573,35 @@ exports.makeClientConstructor = function(methods, serviceName) {
this.updateMetadata = updateMetadata;
}
+ /**
+ * Wait for the client to be ready. The callback will be called when the
+ * client has successfully connected to the server, and it will be called
+ * with an error if the attempt to connect to the server has unrecoverablly
+ * failed or if the deadline expires. This function will make the channel
+ * start connecting if it has not already done so.
+ * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
+ * Infinity to wait forever.
+ * @param {function(Error)} callback The callback to call when done attempting
+ * to connect.
+ */
+ Client.prototype.$waitForReady = function(deadline, callback) {
+ var self = this;
+ var checkState = function(err) {
+ if (err) {
+ callback(new Error('Failed to connect before the deadline'));
+ }
+ var new_state = self.channel.getConnectivityState(true);
+ if (new_state === grpc.connectivityState.READY) {
+ callback();
+ } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
+ callback(new Error('Failed to connect to server'));
+ } else {
+ self.channel.watchConnectivityState(new_state, deadline, checkState);
+ }
+ };
+ checkState();
+ };
+
_.each(methods, function(attrs, name) {
var method_type;
if (attrs.requestStream) {
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 5c62f5990c..5037abae43 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -115,8 +115,10 @@ function waitForCancel(call, emitter) {
* @param {function(*):Buffer=} serialize Serialization function for the
* response
* @param {Object=} metadata Optional trailing metadata to send with status
+ * @param {number=} flags Flags for modifying how the message is sent.
+ * Defaults to 0.
*/
-function sendUnaryResponse(call, value, serialize, metadata) {
+function sendUnaryResponse(call, value, serialize, metadata, flags) {
var end_batch = {};
var status = {
code: grpc.status.OK,
@@ -130,7 +132,9 @@ function sendUnaryResponse(call, value, serialize, metadata) {
end_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
call.metadataSent = true;
}
- end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+ var message = serialize(value);
+ message.grpcWriteFlags = flags;
+ end_batch[grpc.opType.SEND_MESSAGE] = message;
end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
call.startBatch(end_batch, function (){});
}
@@ -254,7 +258,7 @@ function ServerWritableStream(call, serialize) {
* for implementing stream.Writable.
* @access private
* @param {Buffer} chunk The chunk of data to write
- * @param {string} encoding Ignored
+ * @param {string} encoding Used to pass write flags
* @param {function(Error=)} callback Callback to indicate that the write is
* complete
*/
@@ -265,7 +269,13 @@ function _write(chunk, encoding, callback) {
batch[grpc.opType.SEND_INITIAL_METADATA] = {};
this.call.metadataSent = true;
}
- batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ var message = this.serialize(chunk);
+ if (_.isFinite(encoding)) {
+ /* Attach the encoding if it is a finite number. This is the closest we
+ * can get to checking that it is valid flags */
+ message.grpcWriteFlags = encoding;
+ }
+ batch[grpc.opType.SEND_MESSAGE] = message;
this.call.startBatch(batch, function(err, value) {
if (err) {
this.emit('error', err);
@@ -432,6 +442,7 @@ function handleUnary(call, handler, metadata) {
});
emitter.metadata = metadata;
waitForCancel(call, emitter);
+ emitter.call = call;
var batch = {};
batch[grpc.opType.RECV_MESSAGE] = true;
call.startBatch(batch, function(err, result) {
@@ -449,14 +460,14 @@ function handleUnary(call, handler, metadata) {
if (emitter.cancelled) {
return;
}
- handler.func(emitter, function sendUnaryData(err, value, trailer) {
+ handler.func(emitter, function sendUnaryData(err, value, trailer, flags) {
if (err) {
if (trailer) {
err.metadata = trailer;
}
handleError(call, err);
} else {
- sendUnaryResponse(call, value, handler.serialize, trailer);
+ sendUnaryResponse(call, value, handler.serialize, trailer, flags);
}
});
});
@@ -513,7 +524,7 @@ function handleClientStreaming(call, handler, metadata) {
});
waitForCancel(call, stream);
stream.metadata = metadata;
- handler.func(stream, function(err, value, trailer) {
+ handler.func(stream, function(err, value, trailer, flags) {
stream.terminate();
if (err) {
if (trailer) {
@@ -521,7 +532,7 @@ function handleClientStreaming(call, handler, metadata) {
}
handleError(call, err);
} else {
- sendUnaryResponse(call, value, handler.serialize, trailer);
+ sendUnaryResponse(call, value, handler.serialize, trailer, flags);
}
});
}
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
index c991d7b25b..d81df2a36d 100644
--- a/src/node/test/channel_test.js
+++ b/src/node/test/channel_test.js
@@ -36,6 +36,26 @@
var assert = require('assert');
var grpc = require('bindings')('grpc.node');
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
var insecureCreds = grpc.Credentials.createInsecure();
describe('channel', function() {
@@ -86,14 +106,16 @@ describe('channel', function() {
});
});
describe('close', function() {
+ var channel;
+ beforeEach(function() {
+ channel = new grpc.Channel('hostname', insecureCreds, {});
+ });
it('should succeed silently', function() {
- var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
});
});
it('should be idempotent', function() {
- var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
channel.close();
@@ -101,9 +123,68 @@ describe('channel', function() {
});
});
describe('getTarget', function() {
+ var channel;
+ beforeEach(function() {
+ channel = new grpc.Channel('hostname', insecureCreds, {});
+ });
it('should return a string', function() {
- var channel = new grpc.Channel('localhost', insecureCreds, {});
assert.strictEqual(typeof channel.getTarget(), 'string');
});
});
+ describe('getConnectivityState', function() {
+ var channel;
+ beforeEach(function() {
+ channel = new grpc.Channel('hostname', insecureCreds, {});
+ });
+ it('should return IDLE for a new channel', function() {
+ assert.strictEqual(channel.getConnectivityState(),
+ grpc.connectivityState.IDLE);
+ });
+ });
+ describe('watchConnectivityState', function() {
+ var channel;
+ beforeEach(function() {
+ channel = new grpc.Channel('localhost', insecureCreds, {});
+ });
+ afterEach(function() {
+ channel.close();
+ });
+ it('should time out if called alone', function(done) {
+ var old_state = channel.getConnectivityState();
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ channel.watchConnectivityState(old_state, deadline, function(err, value) {
+ assert(err);
+ done();
+ });
+ });
+ it('should complete if a connection attempt is forced', function(done) {
+ var old_state = channel.getConnectivityState();
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ channel.watchConnectivityState(old_state, deadline, function(err, value) {
+ assert.ifError(err);
+ assert.notEqual(value.new_state, old_state);
+ done();
+ });
+ channel.getConnectivityState(true);
+ });
+ it('should complete twice if called twice', function(done) {
+ done = multiDone(done, 2);
+ var old_state = channel.getConnectivityState();
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ channel.watchConnectivityState(old_state, deadline, function(err, value) {
+ assert.ifError(err);
+ assert.notEqual(value.new_state, old_state);
+ done();
+ });
+ channel.watchConnectivityState(old_state, deadline, function(err, value) {
+ assert.ifError(err);
+ assert.notEqual(value.new_state, old_state);
+ done();
+ });
+ channel.getConnectivityState(true);
+ });
+ });
});
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index ecc98ec443..fa06ad4e4d 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -78,6 +78,31 @@ var callErrorNames = [
'INVALID_FLAGS'
];
+/**
+ * List of all propagate flag names
+ * @const
+ * @type {Array.<string>}
+ */
+var propagateFlagNames = [
+ 'DEADLINE',
+ 'CENSUS_STATS_CONTEXT',
+ 'CENSUS_TRACING_CONTEXT',
+ 'CANCELLATION',
+ 'DEFAULTS'
+];
+/*
+ * List of all connectivity state names
+ * @const
+ * @type {Array.<string>}
+ */
+var connectivityStateNames = [
+ 'IDLE',
+ 'CONNECTING',
+ 'READY',
+ 'TRANSIENT_FAILURE',
+ 'FATAL_FAILURE'
+];
+
describe('constants', function() {
it('should have all of the status constants', function() {
for (var i = 0; i < statusNames.length; i++) {
@@ -91,4 +116,16 @@ describe('constants', function() {
'call error missing: ' + callErrorNames[i]);
}
});
+ it('should have all of the propagate flags', function() {
+ for (var i = 0; i < propagateFlagNames.length; i++) {
+ assert(grpc.propagate.hasOwnProperty(propagateFlagNames[i]),
+ 'call error missing: ' + propagateFlagNames[i]);
+ }
+ });
+ it('should have all of the connectivity states', function() {
+ for (var i = 0; i < connectivityStateNames.length; i++) {
+ assert(grpc.connectivityState.hasOwnProperty(connectivityStateNames[i]),
+ 'connectivity status missing: ' + connectivityStateNames[i]);
+ }
+ });
});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index a9df43909e..20c9a07ffa 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -83,7 +83,7 @@ describe('server', function() {
server = new grpc.Server();
});
});
- describe('listen', function() {
+ describe('start', function() {
var server;
before(function() {
server = new grpc.Server();
@@ -92,7 +92,7 @@ describe('server', function() {
after(function() {
server.shutdown();
});
- it('should listen without error', function() {
+ it('should start without error', function() {
assert.doesNotThrow(function() {
server.start();
});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index dda2f8d127..ec7ed87728 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -47,6 +47,27 @@ var mathService = math_proto.lookup('math.Math');
var _ = require('lodash');
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
var server_insecure_creds = grpc.ServerCredentials.createInsecure();
describe('File loader', function() {
@@ -112,6 +133,58 @@ describe('Server.prototype.addProtoService', function() {
});
});
});
+describe('Client#$waitForReady', function() {
+ var server;
+ var port;
+ var Client;
+ var client;
+ before(function() {
+ server = new grpc.Server();
+ port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
+ server.start();
+ Client = surface_client.makeProtobufClientConstructor(mathService);
+ });
+ beforeEach(function() {
+ client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('should complete when called alone', function(done) {
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ done();
+ });
+ });
+ it('should complete when a call is initiated', function(done) {
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ done();
+ });
+ var call = client.div({}, function(err, response) {});
+ call.cancel();
+ });
+ it('should complete if called more than once', function(done) {
+ done = multiDone(done, 2);
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ done();
+ });
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ done();
+ });
+ });
+ it('should complete if called when already ready', function(done) {
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ client.$waitForReady(Infinity, function(error) {
+ assert.ifError(error);
+ done();
+ });
+ });
+ });
+});
describe('Echo service', function() {
var server;
var client;
@@ -272,12 +345,14 @@ describe('Echo metadata', function() {
});
});
describe('Other conditions', function() {
+ var test_service;
+ var Client;
var client;
var server;
var port;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
- var test_service = test_proto.lookup('TestService');
+ test_service = test_proto.lookup('TestService');
server = new grpc.Server();
server.addProtoService(test_service, {
unary: function(call, cb) {
@@ -339,7 +414,7 @@ describe('Other conditions', function() {
}
});
port = server.bind('localhost:0', server_insecure_creds);
- var Client = surface_client.makeProtobufClientConstructor(test_service);
+ Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
@@ -592,6 +667,168 @@ describe('Other conditions', function() {
});
});
});
+ describe('Call propagation', function() {
+ var proxy;
+ var proxy_impl;
+ beforeEach(function() {
+ proxy = new grpc.Server();
+ proxy_impl = {
+ unary: function(call) {},
+ clientStream: function(stream) {},
+ serverStream: function(stream) {},
+ bidiStream: function(stream) {}
+ };
+ });
+ afterEach(function() {
+ console.log('Shutting down server');
+ proxy.shutdown();
+ });
+ describe('Cancellation', function() {
+ it('With a unary call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.unary = function(parent, callback) {
+ client.unary(parent.request, function(err, value) {
+ try {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
+ } finally {
+ callback(err, value);
+ done();
+ }
+ }, null, {parent: parent});
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var call = proxy_client.unary({}, function(err, value) {
+ done();
+ });
+ });
+ it('With a client stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.clientStream = function(parent, callback) {
+ client.clientStream(function(err, value) {
+ try {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
+ } finally {
+ callback(err, value);
+ done();
+ }
+ }, null, {parent: parent});
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var call = proxy_client.clientStream(function(err, value) {
+ done();
+ });
+ });
+ it('With a server stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.serverStream = function(parent) {
+ var child = client.serverStream(parent.request, null,
+ {parent: parent});
+ child.on('error', function(err) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
+ done();
+ });
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var call = proxy_client.serverStream({});
+ call.on('error', function(err) {
+ done();
+ });
+ });
+ it('With a bidi stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.bidiStream = function(parent) {
+ var child = client.bidiStream(null, {parent: parent});
+ child.on('error', function(err) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
+ done();
+ });
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var call = proxy_client.bidiStream();
+ call.on('error', function(err) {
+ done();
+ });
+ });
+ });
+ describe('Deadline', function() {
+ /* jshint bitwise:false */
+ var deadline_flags = (grpc.propagate.DEFAULTS &
+ ~grpc.propagate.CANCELLATION);
+ it('With a client stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.clientStream = function(parent, callback) {
+ client.clientStream(function(err, value) {
+ try {
+ assert(err);
+ assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
+ err.code === grpc.status.INTERNAL);
+ } finally {
+ callback(err, value);
+ done();
+ }
+ }, null, {parent: parent, propagate_flags: deadline_flags});
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ proxy_client.clientStream(function(err, value) {
+ done();
+ }, null, {deadline: deadline});
+ });
+ it('With a bidi stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.bidiStream = function(parent) {
+ var child = client.bidiStream(
+ null, {parent: parent, propagate_flags: deadline_flags});
+ child.on('error', function(err) {
+ assert(err);
+ assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
+ err.code === grpc.status.INTERNAL);
+ done();
+ });
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.Credentials.createInsecure());
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ var call = proxy_client.bidiStream(null, {deadline: deadline});
+ call.on('error', function(err) {
+ done();
+ });
+ });
+ });
+ });
});
describe('Cancelling surface client', function() {
var client;
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index 696069c200..ea2b01ee1d 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -43,7 +43,7 @@
- (instancetype)init {
if ((self = [super init])) {
- _unmanagedQueue = grpc_completion_queue_create();
+ _unmanagedQueue = grpc_completion_queue_create(NULL);
// This is for the following block to capture the pointer by value (instead
// of retaining self and doing self->_unmanagedQueue). This is essential
@@ -64,7 +64,8 @@
while (YES) {
// The following call blocks until an event is available.
grpc_event event = grpc_completion_queue_next(unmanagedQueue,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME),
+ NULL);
GRPCQueueCompletionHandler handler;
switch (event.type) {
case GRPC_OP_COMPLETE:
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index d902f95b51..a7142d0f00 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -97,7 +97,7 @@
queue.unmanagedQueue,
path.UTF8String,
self.hostName.UTF8String,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
- (GRPCChannel *)channel {
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index 070a529629..15b6ffc75c 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -38,7 +38,7 @@
@implementation GRPCUnsecuredChannel
- (instancetype)initWithHost:(NSString *)host {
- return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
+ return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]);
}
// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index 951c051036..fe3d51da53 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -282,7 +282,7 @@
for (GRPCOperation *operation in operations) {
[operation finish];
}
- }));
+ }), NULL);
gpr_free(ops_array);
if (error != GRPC_CALL_OK) {
@@ -293,7 +293,7 @@
}
- (void)cancel {
- grpc_call_cancel(_call);
+ grpc_call_cancel(_call, NULL);
}
- (void)dealloc {
diff --git a/src/php/README.md b/src/php/README.md
index 1804606e09..f432935fde 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -7,17 +7,17 @@ This directory contains source code for PHP implementation of gRPC layered on sh
Alpha : Ready for early adopters
-## ENVIRONMENT
+## Environment
Prerequisite: PHP 5.5 or later, `phpunit`, `pecl`
-Linux:
+**Linux:**
```sh
$ sudo apt-get install php5 php5-dev phpunit php-pear
```
-OS X:
+**Mac OS X:**
```sh
$ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar
@@ -28,10 +28,39 @@ $ curl -O http://pear.php.net/go-pear.phar
$ sudo php -d detect_unicode=0 go-pear.phar
```
-## Build from Homebrew
+## Quick Install
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to
-install gRPC.
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC PHP extension
+
+```sh
+sudo pecl install grpc-alpha
+```
+
+**Mac OS X:**
+
+Install [homebrew][]. Example:
+
+```sh
+ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+
+Install the gRPC core library and the PHP extension in one step
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s php
@@ -39,6 +68,7 @@ $ curl -fsSL https://goo.gl/getgrpc | bash -s php
This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
+
## Build from Source
Clone this repository
@@ -71,7 +101,7 @@ $ sudo make install
Install the gRPC PHP extension
```sh
-$ sudo pecl install grpc
+$ sudo pecl install grpc-alpha
```
OR
@@ -140,6 +170,6 @@ $ ./bin/run_gen_code_test.sh
```
[homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/src/node/examples
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 01ec909b79..252623d0c3 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -216,13 +216,18 @@ PHP_METHOD(Call, __construct) {
char *method;
int method_len;
zval *deadline_obj;
- /* "OsO" == 1 Object, 1 string, 1 Object */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj,
- grpc_ce_channel, &method, &method_len,
- &deadline_obj, grpc_ce_timeval) == FAILURE) {
+ char *host_override = NULL;
+ int host_override_len = 0;
+ /* "OsO|s" == 1 Object, 1 string, 1 Object, 1 optional string */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s",
+ &channel_obj, grpc_ce_channel,
+ &method, &method_len,
+ &deadline_obj, grpc_ce_timeval,
+ &host_override, &host_override_len)
+ == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
- "Call expects a Channel, a String, and a Timeval",
+ "Call expects a Channel, a String, a Timeval and an optional String",
1 TSRMLS_CC);
return;
}
@@ -241,7 +246,7 @@ PHP_METHOD(Call, __construct) {
deadline_obj TSRMLS_CC);
call->wrapped = grpc_channel_create_call(
channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method,
- channel->target, deadline->wrapped);
+ host_override, deadline->wrapped, NULL);
}
/**
@@ -273,7 +278,6 @@ PHP_METHOD(Call, startBatch) {
grpc_byte_buffer *message;
int cancelled;
grpc_call_error error;
- grpc_event event;
zval *result;
char *message_str;
size_t message_len;
@@ -398,23 +402,19 @@ PHP_METHOD(Call, startBatch) {
}
ops[op_num].op = (grpc_op_type)index;
ops[op_num].flags = 0;
+ ops[op_num].reserved = NULL;
op_num++;
}
- error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped);
+ error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
+ NULL);
if (error != GRPC_CALL_OK) {
zend_throw_exception(spl_ce_LogicException,
"start_batch was called incorrectly",
(long)error TSRMLS_CC);
goto cleanup;
}
- event = grpc_completion_queue_pluck(completion_queue, call->wrapped,
- gpr_inf_future(GPR_CLOCK_REALTIME));
- if (!event.success) {
- zend_throw_exception(spl_ce_LogicException,
- "The batch failed for some reason",
- 1 TSRMLS_CC);
- goto cleanup;
- }
+ grpc_completion_queue_pluck(completion_queue, call->wrapped,
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
for (int i = 0; i < op_num; i++) {
switch(ops[i].op) {
case GRPC_OP_SEND_INITIAL_METADATA:
@@ -489,7 +489,7 @@ PHP_METHOD(Call, getPeer) {
PHP_METHOD(Call, cancel) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- grpc_call_cancel(call->wrapped);
+ grpc_call_cancel(call->wrapped, NULL);
}
static zend_function_entry call_methods[] = {
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 7d8a6f87ab..7a981675de 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -51,8 +51,10 @@
#include <grpc/support/log.h>
#include <grpc/grpc_security.h>
-#include "server.h"
+#include "completion_queue.h"
#include "credentials.h"
+#include "server.h"
+#include "timeval.h"
zend_class_entry *grpc_ce_channel;
@@ -62,7 +64,6 @@ void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
}
- efree(channel->target);
efree(channel);
}
@@ -139,9 +140,6 @@ PHP_METHOD(Channel, __construct) {
HashTable *array_hash;
zval **creds_obj = NULL;
wrapped_grpc_credentials *creds = NULL;
- zval **override_obj;
- char *override;
- int override_len;
/* "s|a" == 1 string, 1 optional array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target,
&target_length, &args_array) == FAILURE) {
@@ -149,10 +147,8 @@ PHP_METHOD(Channel, __construct) {
"Channel expects a string and an array", 1 TSRMLS_CC);
return;
}
- override = target;
- override_len = target_length;
if (args_array == NULL) {
- channel->wrapped = grpc_insecure_channel_create(target, NULL);
+ channel->wrapped = grpc_insecure_channel_create(target, NULL, NULL);
} else {
array_hash = Z_ARRVAL_P(args_array);
if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
@@ -167,22 +163,9 @@ PHP_METHOD(Channel, __construct) {
*creds_obj TSRMLS_CC);
zend_hash_del(array_hash, "credentials", 12);
}
- if (zend_hash_find(array_hash, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
- sizeof(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
- (void **)&override_obj) == SUCCESS) {
- if (Z_TYPE_PP(override_obj) != IS_STRING) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
- " must be a string",
- 1 TSRMLS_CC);
- return;
- }
- override = Z_STRVAL_PP(override_obj);
- override_len = Z_STRLEN_PP(override_obj);
- }
php_grpc_read_args_array(args_array, &args);
if (creds == NULL) {
- channel->wrapped = grpc_insecure_channel_create(target, &args);
+ channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
} else {
gpr_log(GPR_DEBUG, "Initialized secure channel");
channel->wrapped =
@@ -190,8 +173,6 @@ PHP_METHOD(Channel, __construct) {
}
efree(args.args);
}
- channel->target = ecalloc(override_len + 1, sizeof(char));
- memcpy(channel->target, override, override_len);
}
/**
@@ -205,6 +186,59 @@ PHP_METHOD(Channel, getTarget) {
}
/**
+ * Get the connectivity state of the channel
+ * @param bool (optional) try to connect on the channel
+ * @return long The grpc connectivity state
+ */
+PHP_METHOD(Channel, getConnectivityState) {
+ wrapped_grpc_channel *channel =
+ (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ bool try_to_connect;
+ /* "|b" == 1 optional bool */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect) ==
+ FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "getConnectivityState expects a bool", 1 TSRMLS_CC);
+ return;
+ }
+ RETURN_LONG(grpc_channel_check_connectivity_state(channel->wrapped,
+ (int)try_to_connect));
+}
+
+/**
+ * Watch the connectivity state of the channel until it changed
+ * @param long The previous connectivity state of the channel
+ * @param Timeval The deadline this function should wait until
+ * @return bool If the connectivity state changes from last_state
+ * before deadline
+ */
+PHP_METHOD(Channel, watchConnectivityState) {
+ wrapped_grpc_channel *channel =
+ (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long last_state;
+ zval *deadline_obj;
+ /* "lO" == 1 long 1 object */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
+ &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "watchConnectivityState expects 1 long 1 timeval",
+ 1 TSRMLS_CC);
+ return;
+ }
+
+ wrapped_grpc_timeval *deadline =
+ (wrapped_grpc_timeval *)zend_object_store_get_object(
+ deadline_obj TSRMLS_CC);
+ grpc_channel_watch_connectivity_state(
+ channel->wrapped, (grpc_connectivity_state)last_state,
+ deadline->wrapped, completion_queue, NULL);
+ grpc_event event = grpc_completion_queue_pluck(
+ completion_queue, NULL,
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+ RETURN_BOOL(event.success);
+}
+
+/**
* Close the channel
*/
PHP_METHOD(Channel, close) {
@@ -219,6 +253,8 @@ PHP_METHOD(Channel, close) {
static zend_function_entry channel_methods[] = {
PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END};
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index c13fa4c6d7..78a16ed0c9 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -53,7 +53,6 @@ typedef struct wrapped_grpc_channel {
zend_object std;
grpc_channel *wrapped;
- char *target;
} wrapped_grpc_channel;
/* Initializes the Channel class */
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
index c653a592ef..741204b0b1 100644
--- a/src/php/ext/grpc/completion_queue.c
+++ b/src/php/ext/grpc/completion_queue.c
@@ -38,14 +38,13 @@
grpc_completion_queue *completion_queue;
void grpc_php_init_completion_queue(TSRMLS_D) {
- completion_queue = grpc_completion_queue_create();
+ completion_queue = grpc_completion_queue_create(NULL);
}
void grpc_php_shutdown_completion_queue(TSRMLS_D) {
grpc_completion_queue_shutdown(completion_queue);
while (grpc_completion_queue_next(completion_queue,
- gpr_inf_future(GPR_CLOCK_REALTIME))
- .type != GRPC_QUEUE_SHUTDOWN)
- ;
+ gpr_inf_future(GPR_CLOCK_REALTIME),
+ NULL).type != GRPC_QUEUE_SHUTDOWN);
grpc_completion_queue_destroy(completion_queue);
}
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index fedcf0f539..0f730ea756 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -183,6 +183,18 @@ PHP_MINIT_FUNCTION(grpc) {
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
+ /* Register connectivity state constants */
+ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
+ GRPC_CHANNEL_IDLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
+ GRPC_CHANNEL_CONNECTING, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
+ GRPC_CHANNEL_READY, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
+ GRPC_CHANNEL_TRANSIENT_FAILURE, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_FATAL_FAILURE",
+ GRPC_CHANNEL_FATAL_FAILURE, CONST_CS);
+
grpc_init_call(TSRMLS_C);
grpc_init_channel(TSRMLS_C);
grpc_init_server(TSRMLS_C);
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index d58aa884ca..ca129e76ca 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -66,7 +66,7 @@ void free_wrapped_grpc_server(void *object TSRMLS_DC) {
grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
grpc_server_cancel_all_calls(server->wrapped);
grpc_completion_queue_pluck(completion_queue, NULL,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
grpc_server_destroy(server->wrapped);
}
efree(server);
@@ -109,13 +109,14 @@ PHP_METHOD(Server, __construct) {
return;
}
if (args_array == NULL) {
- server->wrapped = grpc_server_create(NULL);
+ server->wrapped = grpc_server_create(NULL, NULL);
} else {
php_grpc_read_args_array(args_array, &args);
- server->wrapped = grpc_server_create(&args);
+ server->wrapped = grpc_server_create(&args, NULL);
efree(args.args);
}
- grpc_server_register_completion_queue(server->wrapped, completion_queue);
+ grpc_server_register_completion_queue(server->wrapped, completion_queue,
+ NULL);
}
/**
@@ -146,7 +147,7 @@ PHP_METHOD(Server, requestCall) {
goto cleanup;
}
event = grpc_completion_queue_pluck(completion_queue, NULL,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
if (!event.success) {
zend_throw_exception(spl_ce_LogicException,
"Failed to request a call for some reason",
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index a0c677908c..2e980c5eed 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -75,6 +75,51 @@ class BaseStub {
}
/**
+ * @param $try_to_connect bool
+ * @return int The grpc connectivity state
+ */
+ public function getConnectivityState($try_to_connect = false) {
+ return $this->channel->getConnectivityState($try_to_connect);
+ }
+
+ /**
+ * @param $timeout in microseconds
+ * @return bool true if channel is ready
+ * @throw Exception if channel is in FATAL_ERROR state
+ */
+ public function waitForReady($timeout) {
+ $new_state = $this->getConnectivityState(true);
+ if ($this->_checkConnectivityState($new_state)) {
+ return true;
+ }
+
+ $now = Timeval::now();
+ $delta = new Timeval($timeout);
+ $deadline = $now->add($delta);
+
+ while ($this->channel->watchConnectivityState($new_state, $deadline)) {
+ // state has changed before deadline
+ $new_state = $this->getConnectivityState();
+ if ($this->_checkConnectivityState($new_state)) {
+ return true;
+ }
+ }
+ // deadline has passed
+ $new_state = $this->getConnectivityState();
+ return $this->_checkConnectivityState($new_state);
+ }
+
+ private function _checkConnectivityState($new_state) {
+ if ($new_state == \Grpc\CHANNEL_READY) {
+ return true;
+ }
+ if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
+ throw new Exception('Failed to connect to server');
+ }
+ return false;
+ }
+
+ /**
* Close the communication channel associated with this stub
*/
public function close() {
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 44e6242c29..376d306da0 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -271,7 +271,7 @@ function cancelAfterFirstResponse($stub) {
}
function timeoutOnSleepingServer($stub) {
- $call = $stub->FullDuplexCall(array('timeout' => 500000));
+ $call = $stub->FullDuplexCall(array('timeout' => 1000));
$request = new grpc\testing\StreamingOutputCallRequest();
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE);
$response_parameters = new grpc\testing\ResponseParameters();
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 27e27cdfdf..4c0cf91d51 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -153,4 +153,50 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
public function testGetTarget() {
$this->assertTrue(is_string($this->channel->getTarget()));
}
+
+ public function testGetConnectivityState() {
+ $this->assertTrue($this->channel->getConnectivityState() == Grpc\CHANNEL_IDLE);
+ }
+
+ public function testWatchConnectivityStateFailed() {
+ $idle_state = $this->channel->getConnectivityState(true);
+ $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+ $now = Grpc\Timeval::now();
+ $delta = new Grpc\Timeval(1);
+ $deadline = $now->add($delta);
+
+ $this->assertFalse($this->channel->watchConnectivityState(
+ $idle_state, $deadline));
+ }
+
+ public function testWatchConnectivityStateSuccess() {
+ $idle_state = $this->channel->getConnectivityState(true);
+ $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+ $now = Grpc\Timeval::now();
+ $delta = new Grpc\Timeval(3000000); // should finish well before
+ $deadline = $now->add($delta);
+
+ $this->assertTrue($this->channel->watchConnectivityState(
+ $idle_state, $deadline));
+
+ $new_state = $this->channel->getConnectivityState();
+ $this->assertTrue($idle_state != $new_state);
+ }
+
+ public function testWatchConnectivityStateDoNothing() {
+ $idle_state = $this->channel->getConnectivityState();
+ $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+ $now = Grpc\Timeval::now();
+ $delta = new Grpc\Timeval(100000);
+ $deadline = $now->add($delta);
+
+ $this->assertFalse($this->channel->watchConnectivityState(
+ $idle_state, $deadline));
+
+ $new_state = $this->channel->getConnectivityState();
+ $this->assertTrue($new_state == Grpc\CHANNEL_IDLE);
+ }
}
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index f91c006da5..60341b983d 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -40,13 +40,15 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
file_get_contents(dirname(__FILE__) . '/../data/server1.key'),
file_get_contents(dirname(__FILE__) . '/../data/server1.pem'));
$this->server = new Grpc\Server();
- $port = $this->server->addSecureHttp2Port('0.0.0.0:0',
+ $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0',
$server_credentials);
$this->server->start();
+ $this->host_override = 'foo.test.google.fr';
$this->channel = new Grpc\Channel(
- 'localhost:' . $port,
+ 'localhost:' . $this->port,
[
- 'grpc.ssl_target_name_override' => 'foo.test.google.fr',
+ 'grpc.ssl_target_name_override' => $this->host_override,
+ 'grpc.default_authority' => $this->host_override,
'credentials' => $credentials
]);
}
@@ -61,7 +63,8 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$status_text = 'xyz';
$call = new Grpc\Call($this->channel,
'dummy_method',
- $deadline);
+ $deadline,
+ $this->host_override);
$event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
@@ -112,7 +115,8 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$call = new Grpc\Call($this->channel,
'dummy_method',
- $deadline);
+ $deadline,
+ $this->host_override);
$event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
diff --git a/src/python/README.md b/src/python/README.md
index 2beb3a913a..de0142db05 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -9,12 +9,36 @@ Alpha : Ready for early adopters
PREREQUISITES
-------------
- Python 2.7, virtualenv, pip
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core.
INSTALLATION
-------------
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Python.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC Python module
+
+```sh
+sudo pip install grpcio
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Python.
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s python
```
@@ -27,11 +51,6 @@ Please read our online documentation for a [Quick Start][] and a [detailed examp
BUILDING FROM SOURCE
---------------------
- Clone this repository
-- Build the gRPC core from the root of the
- [gRPC Git repository](https://github.com/grpc/grpc)
-```
-$ make shared_c static_c
-```
- Use build_python.sh to build the Python code and install it into a virtual environment
```
@@ -60,7 +79,7 @@ $ ../../tools/distrib/python/submit.py
```
[homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html
[detailed example]:http://www.grpc.io/docs/installation/python.html
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 00bdecf56f..c7b5a3bde4 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -6,7 +6,7 @@ Package for GRPC Python.
Dependencies
------------
-Ensure you have installed the gRPC core. On Mac OS X, install homebrew_. On Linux, install linuxbrew_.
+Ensure you have installed the gRPC core. On Mac OS X, install homebrew_.
Run the following command to install gRPC Python.
::
@@ -19,5 +19,4 @@ Otherwise, `install from source`_
.. _`install from source`: https://github.com/grpc/grpc/blob/master/src/python/README.md#building-from-source
.. _homebrew: http://brew.sh
-.. _linuxbrew: https://github.com/Homebrew/linuxbrew#installation
.. _`gRPC install script`: https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
index 5e46605c45..42a50151f6 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/call.c
@@ -132,7 +132,7 @@ PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs)
}
}
tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops);
- errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag);
+ errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL);
gpr_free(ops);
return PyInt_FromLong(errcode);
}
@@ -152,13 +152,13 @@ PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) {
return NULL;
}
code = PyInt_AsLong(py_code);
- errcode = grpc_call_cancel_with_status(self->c_call, code, details);
+ errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL);
} else if (py_code != NULL || details != NULL) {
PyErr_SetString(PyExc_ValueError,
"if `code` is specified, so must `details`");
return NULL;
} else {
- errcode = grpc_call_cancel(self->c_call);
+ errcode = grpc_call_cancel(self->c_call, NULL);
}
return PyInt_FromLong(errcode);
}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
index eb9d43d154..c577ac05eb 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
@@ -108,7 +108,7 @@ Channel *pygrpc_Channel_new(
if (creds) {
self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
} else {
- self->c_chan = grpc_insecure_channel_create(target, &c_args);
+ self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL);
}
pygrpc_discard_channel_args(c_args);
return self;
@@ -133,7 +133,7 @@ Call *pygrpc_Channel_create_call(
call = pygrpc_Call_new_empty(cq);
call->c_call = grpc_channel_create_call(
self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
- pygrpc_cast_double_to_gpr_timespec(deadline));
+ pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
return call;
}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
index 2dd44b6ddd..d8bb89ca4b 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
@@ -90,7 +90,7 @@ PyTypeObject pygrpc_CompletionQueue_type = {
CompletionQueue *pygrpc_CompletionQueue_new(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0);
- self->c_cq = grpc_completion_queue_create();
+ self->c_cq = grpc_completion_queue_create(NULL);
return self;
}
@@ -111,7 +111,7 @@ PyObject *pygrpc_CompletionQueue_next(
}
Py_BEGIN_ALLOW_THREADS;
event = grpc_completion_queue_next(
- self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline));
+ self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
Py_END_ALLOW_THREADS;
transliterated_event = pygrpc_consume_event(event);
return transliterated_event;
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c
index 2a11d09d21..15c98f28eb 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/server.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/server.c
@@ -104,8 +104,8 @@ Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
return NULL;
}
self = (Server *)type->tp_alloc(type, 0);
- self->c_serv = grpc_server_create(&c_args);
- grpc_server_register_completion_queue(self->c_serv, cq->c_cq);
+ self->c_serv = grpc_server_create(&c_args, NULL);
+ grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL);
pygrpc_discard_channel_args(c_args);
self->cq = cq;
Py_INCREF(self->cq);
diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c
index 2eea0e18ef..590f7e013a 100644
--- a/src/python/grpcio/grpc/_adapter/_c/utility.c
+++ b/src/python/grpcio/grpc/_adapter/_c/utility.c
@@ -184,6 +184,7 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) {
return 0;
}
c_op.op = type;
+ c_op.reserved = NULL;
c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
if (PyErr_Occurred()) {
return 0;
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index 7783e91824..5c636d61ab 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -44,7 +44,10 @@ from grpc.framework.interfaces.links import links
@enum.unique
class _Read(enum.Enum):
READING = 'reading'
- AWAITING_ALLOWANCE = 'awaiting allowance'
+ # TODO(issue 2916): This state will again be necessary after eliminating the
+ # "early_read" field of _RPCState and going back to only reading when granted
+ # allowance to read.
+ # AWAITING_ALLOWANCE = 'awaiting allowance'
CLOSED = 'closed'
@@ -67,12 +70,15 @@ class _RPCState(object):
def __init__(
self, request_deserializer, response_serializer, sequence_number, read,
- allowance, high_write, low_write, premetadataed, terminal_metadata, code,
- message):
+ early_read, allowance, high_write, low_write, premetadataed,
+ terminal_metadata, code, message):
self.request_deserializer = request_deserializer
self.response_serializer = response_serializer
self.sequence_number = sequence_number
self.read = read
+ # TODO(issue 2916): Eliminate this by eliminating the necessity of calling
+ # call.read just to advance the RPC.
+ self.early_read = early_read # A raw (not deserialized) read.
self.allowance = allowance
self.high_write = high_write
self.low_write = low_write
@@ -120,7 +126,7 @@ class _Kernel(object):
call.read(call)
self._rpc_states[call] = _RPCState(
- request_deserializer, response_serializer, 1, _Read.READING, 0,
+ request_deserializer, response_serializer, 1, _Read.READING, None, 1,
_HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None)
ticket = links.Ticket(
call, 0, group, method, links.Ticket.Subscription.FULL,
@@ -140,12 +146,15 @@ class _Kernel(object):
termination = links.Ticket.Termination.COMPLETION
else:
if 0 < rpc_state.allowance:
+ payload = rpc_state.request_deserializer(event.bytes)
+ termination = None
rpc_state.allowance -= 1
call.read(call)
else:
- rpc_state.read = _Read.AWAITING_ALLOWANCE
- payload = rpc_state.request_deserializer(event.bytes)
- termination = None
+ rpc_state.early_read = event.bytes
+ return
+ # TODO(issue 2916): Instead of returning:
+ # rpc_state.read = _Read.AWAITING_ALLOWANCE
ticket = links.Ticket(
call, rpc_state.sequence_number, None, None, None, None, None, None,
payload, None, None, None, termination)
@@ -237,12 +246,22 @@ class _Kernel(object):
rpc_state.premetadataed = True
if ticket.allowance is not None:
- if rpc_state.read is _Read.AWAITING_ALLOWANCE:
- rpc_state.allowance += ticket.allowance - 1
- call.read(call)
- rpc_state.read = _Read.READING
- else:
+ if rpc_state.early_read is None:
rpc_state.allowance += ticket.allowance
+ else:
+ payload = rpc_state.request_deserializer(rpc_state.early_read)
+ rpc_state.allowance += ticket.allowance - 1
+ rpc_state.early_read = None
+ if rpc_state.read is _Read.READING:
+ call.read(call)
+ termination = None
+ else:
+ termination = links.Ticket.Termination.COMPLETION
+ ticket = links.Ticket(
+ call, rpc_state.sequence_number, None, None, None, None, None,
+ None, payload, None, None, None, termination)
+ rpc_state.sequence_number += 1
+ self._relay.add_value(ticket)
if ticket.payload is not None:
call.write(rpc_state.response_serializer(ticket.payload), call)
diff --git a/src/python/grpcio/grpc/early_adopter/implementations.py b/src/python/grpcio/grpc/early_adopter/implementations.py
index 10919fae69..9c396aa7ad 100644
--- a/src/python/grpcio/grpc/early_adopter/implementations.py
+++ b/src/python/grpcio/grpc/early_adopter/implementations.py
@@ -41,13 +41,15 @@ from grpc.framework.base import util as _base_utilities
from grpc.framework.face import implementations as _face_implementations
from grpc.framework.foundation import logging_pool
-_THREAD_POOL_SIZE = 8
+_DEFAULT_THREAD_POOL_SIZE = 8
_ONE_DAY_IN_SECONDS = 24 * 60 * 60
class _Server(interfaces.Server):
- def __init__(self, breakdown, port, private_key, certificate_chain):
+ def __init__(
+ self, breakdown, port, private_key, certificate_chain,
+ thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
self._lock = threading.Lock()
self._breakdown = breakdown
self._port = port
@@ -56,6 +58,7 @@ class _Server(interfaces.Server):
else:
self._key_chain_pairs = ((private_key, certificate_chain),)
+ self._pool_size = thread_pool_size
self._pool = None
self._back = None
self._fore_link = None
@@ -63,7 +66,7 @@ class _Server(interfaces.Server):
def _start(self):
with self._lock:
if self._pool is None:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ self._pool = logging_pool.pool(self._pool_size)
servicer = _face_implementations.servicer(
self._pool, self._breakdown.implementations, None)
self._back = _base_implementations.back_link(
@@ -114,7 +117,8 @@ class _Stub(interfaces.Stub):
def __init__(
self, breakdown, host, port, secure, root_certificates, private_key,
- certificate_chain, metadata_transformer=None, server_host_override=None):
+ certificate_chain, metadata_transformer=None, server_host_override=None,
+ thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
self._lock = threading.Lock()
self._breakdown = breakdown
self._host = host
@@ -126,6 +130,7 @@ class _Stub(interfaces.Stub):
self._metadata_transformer = metadata_transformer
self._server_host_override = server_host_override
+ self._pool_size = thread_pool_size
self._pool = None
self._front = None
self._rear_link = None
@@ -134,7 +139,7 @@ class _Stub(interfaces.Stub):
def __enter__(self):
with self._lock:
if self._pool is None:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ self._pool = logging_pool.pool(self._pool_size)
self._front = _base_implementations.front_link(
self._pool, self._pool, self._pool)
self._rear_link = _rear.RearLink(
@@ -193,7 +198,7 @@ class _Stub(interfaces.Stub):
def stub(
service_name, methods, host, port, metadata_transformer=None, secure=False,
root_certificates=None, private_key=None, certificate_chain=None,
- server_host_override=None):
+ server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
"""Constructs an interfaces.Stub.
Args:
@@ -216,6 +221,8 @@ def stub(
certificate chain should be used.
server_host_override: (For testing only) the target name used for SSL
host name checking.
+ thread_pool_size: The maximum number of threads to allow in the backing
+ thread pool.
Returns:
An interfaces.Stub affording RPC invocation.
@@ -224,11 +231,13 @@ def stub(
return _Stub(
breakdown, host, port, secure, root_certificates, private_key,
certificate_chain, server_host_override=server_host_override,
- metadata_transformer=metadata_transformer)
+ metadata_transformer=metadata_transformer,
+ thread_pool_size=thread_pool_size)
def server(
- service_name, methods, port, private_key=None, certificate_chain=None):
+ service_name, methods, port, private_key=None, certificate_chain=None,
+ thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
"""Constructs an interfaces.Server.
Args:
@@ -242,9 +251,12 @@ def server(
private_key: A pem-encoded private key, or None for an insecure server.
certificate_chain: A pem-encoded certificate chain, or None for an insecure
server.
+ thread_pool_size: The maximum number of threads to allow in the backing
+ thread pool.
Returns:
An interfaces.Server that will serve secure traffic.
"""
breakdown = _face_utilities.break_down_service(service_name, methods)
- return _Server(breakdown, port, private_key, certificate_chain)
+ return _Server(breakdown, port, private_key, certificate_chain,
+ thread_pool_size=thread_pool_size)
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py
index 5948b50eaa..7086519106 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py
@@ -27,17 +27,4 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# source: test/cpp/interop/test.proto
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
- module Testing
- end
-end
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py
new file mode 100644
index 0000000000..9d1651daac
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py
@@ -0,0 +1,273 @@
+# 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.
+
+"""The base interface of RPC Framework."""
+
+import abc
+import enum
+
+# abandonment is referenced from specification in this module.
+from grpc.framework.foundation import abandonment # pylint: disable=unused-import
+
+
+class NoSuchMethodError(Exception):
+ """Indicates that an unrecognized operation has been called."""
+
+
+@enum.unique
+class Outcome(enum.Enum):
+ """Operation outcomes."""
+
+ COMPLETED = 'completed'
+ CANCELLED = 'cancelled'
+ EXPIRED = 'expired'
+ LOCAL_SHUTDOWN = 'local shutdown'
+ REMOTE_SHUTDOWN = 'remote shutdown'
+ RECEPTION_FAILURE = 'reception failure'
+ TRANSMISSION_FAILURE = 'transmission failure'
+ LOCAL_FAILURE = 'local failure'
+ REMOTE_FAILURE = 'remote failure'
+
+
+class Completion(object):
+ """An aggregate of the values exchanged upon operation completion.
+
+ Attributes:
+ terminal_metadata: A terminal metadata value for the operaton.
+ code: A code value for the operation.
+ message: A message value for the operation.
+ """
+ __metaclass__ = abc.ABCMeta
+
+
+class OperationContext(object):
+ """Provides operation-related information and action."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def outcome(self):
+ """Indicates the operation's outcome (or that the operation is ongoing).
+
+ Returns:
+ None if the operation is still active or the Outcome value for the
+ operation if it has terminated.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def add_termination_callback(self, callback):
+ """Adds a function to be called upon operation termination.
+
+ Args:
+ callback: A callable to be passed an Outcome value on operation
+ termination.
+
+ Returns:
+ None if the operation has not yet terminated and the passed callback will
+ later be called when it does terminate, or if the operation has already
+ terminated an Outcome value describing the operation termination and the
+ passed callback will not be called as a result of this method call.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def time_remaining(self):
+ """Describes the length of allowed time remaining for the operation.
+
+ Returns:
+ A nonnegative float indicating the length of allowed time in seconds
+ remaining for the operation to complete before it is considered to have
+ timed out. Zero is returned if the operation has terminated.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def cancel(self):
+ """Cancels the operation if the operation has not yet terminated."""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def fail(self, exception):
+ """Indicates that the operation has failed.
+
+ Args:
+ exception: An exception germane to the operation failure. May be None.
+ """
+ raise NotImplementedError()
+
+
+class Operator(object):
+ """An interface through which to participate in an operation."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def advance(
+ self, initial_metadata=None, payload=None, completion=None,
+ allowance=None):
+ """Progresses the operation.
+
+ Args:
+ initial_metadata: An initial metadata value. Only one may ever be
+ communicated in each direction for an operation, and they must be
+ communicated no later than either the first payload or the completion.
+ payload: A payload value.
+ completion: A Completion value. May only ever be non-None once in either
+ direction, and no payloads may be passed after it has been communicated.
+ allowance: A positive integer communicating the number of additional
+ payloads allowed to be passed by the remote side of the operation.
+ """
+ raise NotImplementedError()
+
+
+class Subscription(object):
+ """Describes customer code's interest in values from the other side.
+
+ Attributes:
+ kind: A Kind value describing the overall kind of this value.
+ termination_callback: A callable to be passed the Outcome associated with
+ the operation after it has terminated. Must be non-None if kind is
+ Kind.TERMINATION_ONLY. Must be None otherwise.
+ allowance: A callable behavior that accepts positive integers representing
+ the number of additional payloads allowed to be passed to the other side
+ of the operation. Must be None if kind is Kind.FULL. Must not be None
+ otherwise.
+ operator: An Operator to be passed values from the other side of the
+ operation. Must be non-None if kind is Kind.FULL. Must be None otherwise.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+
+ NONE = 'none'
+ TERMINATION_ONLY = 'termination only'
+ FULL = 'full'
+
+
+class Servicer(object):
+ """Interface for service implementations."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def service(self, group, method, context, output_operator):
+ """Services an operation.
+
+ Args:
+ group: The group identifier of the operation to be serviced.
+ method: The method identifier of the operation to be serviced.
+ context: An OperationContext object affording contextual information and
+ actions.
+ output_operator: An Operator that will accept output values of the
+ operation.
+
+ Returns:
+ A Subscription via which this object may or may not accept more values of
+ the operation.
+
+ Raises:
+ NoSuchMethodError: If this Servicer does not handle operations with the
+ given group and method.
+ abandonment.Abandoned: If the operation has been aborted and there no
+ longer is any reason to service the operation.
+ """
+ raise NotImplementedError()
+
+
+class End(object):
+ """Common type for entry-point objects on both sides of an operation."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def start(self):
+ """Starts this object's service of operations."""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop_gracefully(self):
+ """Gracefully stops this object's service of operations.
+
+ Operations in progress will be allowed to complete, and this method blocks
+ until all of them have.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop_immediately(self):
+ """Immediately stops this object's service of operations.
+
+ Operations in progress will not be allowed to complete.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def operate(
+ self, group, method, subscription, timeout, initial_metadata=None,
+ payload=None, completion=None):
+ """Commences an operation.
+
+ Args:
+ group: The group identifier of the invoked operation.
+ method: The method identifier of the invoked operation.
+ subscription: A Subscription to which the results of the operation will be
+ passed.
+ timeout: A length of time in seconds to allow for the operation.
+ initial_metadata: An initial metadata value to be sent to the other side
+ of the operation. May be None if the initial metadata will be later
+ passed via the returned operator or if there will be no initial metadata
+ passed at all.
+ payload: An initial payload for the operation.
+ completion: A Completion value indicating the end of transmission to the
+ other side of the operation.
+
+ Returns:
+ A pair of objects affording information about the operation and action
+ continuing the operation. The first element of the returned pair is an
+ OperationContext for the operation and the second element of the
+ returned pair is an Operator to which operation values not passed in
+ this call should later be passed.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def operation_stats(self):
+ """Reports the number of terminated operations broken down by outcome.
+
+ Returns:
+ A dictionary from Outcome value to an integer identifying the number
+ of operations that terminated with that outcome.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def add_idle_action(self, action):
+ """Adds an action to be called when this End has no ongoing operations.
+
+ Args:
+ action: A callable that accepts no arguments.
+ """
+ raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/utilities.py b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
new file mode 100644
index 0000000000..a9ee1a0981
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
@@ -0,0 +1,79 @@
+# 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.
+
+"""Utilities for use with the base interface of RPC Framework."""
+
+import collections
+
+from grpc.framework.interfaces.base import base
+
+
+class _Completion(
+ base.Completion,
+ collections.namedtuple(
+ '_Completion', ('terminal_metadata', 'code', 'message',))):
+ """A trivial implementation of base.Completion."""
+
+
+class _Subscription(
+ base.Subscription,
+ collections.namedtuple(
+ '_Subscription',
+ ('kind', 'termination_callback', 'allowance', 'operator',))):
+ """A trivial implementation of base.Subscription."""
+
+_NONE_SUBSCRIPTION = _Subscription(
+ base.Subscription.Kind.NONE, None, None, None)
+
+
+def completion(terminal_metadata, code, message):
+ """Creates a base.Completion aggregating the given operation values.
+
+ Args:
+ terminal_metadata: A terminal metadata value for an operaton.
+ code: A code value for an operation.
+ message: A message value for an operation.
+
+ Returns:
+ A base.Completion aggregating the given operation values.
+ """
+ return _Completion(terminal_metadata, code, message)
+
+
+def full_subscription(operator):
+ """Creates a "full" base.Subscription for the given base.Operator.
+
+ Args:
+ operator: A base.Operator to be used in an operation.
+
+ Returns:
+ A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given
+ base.Operator.
+ """
+ return _Subscription(base.Subscription.Kind.FULL, None, None, operator)
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py b/src/python/grpcio_test/grpc_test/framework/common/test_constants.py
index 3126d0d82c..e1d3c2709d 100644
--- a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py
+++ b/src/python/grpcio_test/grpc_test/framework/common/test_constants.py
@@ -29,15 +29,25 @@
"""Constants shared among tests throughout RPC Framework."""
+# Value for maximum duration in seconds that a test is allowed for its actual
+# behavioral logic, excluding all time spent deliberately waiting in the test.
+TIME_ALLOWANCE = 10
# Value for maximum duration in seconds of RPCs that may time out as part of a
# test.
SHORT_TIMEOUT = 4
# Absurdly large value for maximum duration in seconds for should-not-time-out
# RPCs made during tests.
LONG_TIMEOUT = 3000
+# Values to supply on construction of an object that will service RPCs; these
+# should not be used as the actual timeout values of any RPCs made during tests.
+DEFAULT_TIMEOUT = 300
+MAXIMUM_TIMEOUT = 3600
# The number of payloads to transmit in streaming tests.
STREAM_LENGTH = 200
+# The size of payloads to transmit in tests.
+PAYLOAD_SIZE = 256 * 1024 + 17
+
# The size of thread pools to use in tests.
POOL_SIZE = 10
diff --git a/src/ruby/bin/interop/test/cpp/interop/empty.rb b/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py
index 3579fa5ded..7086519106 100644
--- a/src/ruby/bin/interop/test/cpp/interop/empty.rb
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py
@@ -27,18 +27,4 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# source: test/cpp/interop/empty.proto
-require 'google/protobuf'
-
-Google::Protobuf::DescriptorPool.generated_pool.build do
- add_message "grpc.testing.Empty" do
- end
-end
-
-module Grpc
- module Testing
- Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
- end
-end
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
new file mode 100644
index 0000000000..e4d2a7a0d7
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
@@ -0,0 +1,568 @@
+# 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.
+
+"""Part of the tests of the base interface of RPC Framework."""
+
+import abc
+import collections
+import enum
+import random # pylint: disable=unused-import
+import threading
+import time
+
+from grpc.framework.interfaces.base import base
+from grpc_test.framework.common import test_constants
+from grpc_test.framework.interfaces.base import _sequence
+from grpc_test.framework.interfaces.base import _state
+from grpc_test.framework.interfaces.base import test_interfaces # pylint: disable=unused-import
+
+_GROUP = 'base test cases test group'
+_METHOD = 'base test cases test method'
+
+_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE = test_constants.PAYLOAD_SIZE / 20
+_MINIMUM_PAYLOAD_SIZE = test_constants.PAYLOAD_SIZE / 600
+
+
+def _create_payload(randomness):
+ length = randomness.randint(
+ _MINIMUM_PAYLOAD_SIZE, test_constants.PAYLOAD_SIZE)
+ random_section_length = randomness.randint(
+ 0, min(_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE, length))
+ random_section = bytes(
+ bytearray(
+ randomness.getrandbits(8) for _ in range(random_section_length)))
+ sevens_section = '\x07' * (length - random_section_length)
+ return b''.join(randomness.sample((random_section, sevens_section), 2))
+
+
+def _anything_in_flight(state):
+ return (
+ state.invocation_initial_metadata_in_flight is not None or
+ state.invocation_payloads_in_flight or
+ state.invocation_completion_in_flight is not None or
+ state.service_initial_metadata_in_flight is not None or
+ state.service_payloads_in_flight or
+ state.service_completion_in_flight is not None or
+ 0 < state.invocation_allowance_in_flight or
+ 0 < state.service_allowance_in_flight
+ )
+
+
+def _verify_service_advance_and_update_state(
+ initial_metadata, payload, completion, allowance, state, implementation):
+ if initial_metadata is not None:
+ if state.invocation_initial_metadata_received:
+ return 'Later invocation initial metadata received: %s' % (
+ initial_metadata,)
+ if state.invocation_payloads_received:
+ return 'Invocation initial metadata received after payloads: %s' % (
+ state.invocation_payloads_received)
+ if state.invocation_completion_received:
+ return 'Invocation initial metadata received after invocation completion!'
+ if not implementation.metadata_transmitted(
+ state.invocation_initial_metadata_in_flight, initial_metadata):
+ return 'Invocation initial metadata maltransmitted: %s, %s' % (
+ state.invocation_initial_metadata_in_flight, initial_metadata)
+ else:
+ state.invocation_initial_metadata_in_flight = None
+ state.invocation_initial_metadata_received = True
+
+ if payload is not None:
+ if state.invocation_completion_received:
+ return 'Invocation payload received after invocation completion!'
+ elif not state.invocation_payloads_in_flight:
+ return 'Invocation payload "%s" received but not in flight!' % (payload,)
+ elif state.invocation_payloads_in_flight[0] != payload:
+ return 'Invocation payload mismatch: %s, %s' % (
+ state.invocation_payloads_in_flight[0], payload)
+ elif state.service_side_invocation_allowance < 1:
+ return 'Disallowed invocation payload!'
+ else:
+ state.invocation_payloads_in_flight.pop(0)
+ state.invocation_payloads_received += 1
+ state.service_side_invocation_allowance -= 1
+
+ if completion is not None:
+ if state.invocation_completion_received:
+ return 'Later invocation completion received: %s' % (completion,)
+ elif not implementation.completion_transmitted(
+ state.invocation_completion_in_flight, completion):
+ return 'Invocation completion maltransmitted: %s, %s' % (
+ state.invocation_completion_in_flight, completion)
+ else:
+ state.invocation_completion_in_flight = None
+ state.invocation_completion_received = True
+
+ if allowance is not None:
+ if allowance <= 0:
+ return 'Illegal allowance value: %s' % (allowance,)
+ else:
+ state.service_allowance_in_flight -= allowance
+ state.service_side_service_allowance += allowance
+
+
+def _verify_invocation_advance_and_update_state(
+ initial_metadata, payload, completion, allowance, state, implementation):
+ if initial_metadata is not None:
+ if state.service_initial_metadata_received:
+ return 'Later service initial metadata received: %s' % (initial_metadata,)
+ if state.service_payloads_received:
+ return 'Service initial metadata received after service payloads: %s' % (
+ state.service_payloads_received)
+ if state.service_completion_received:
+ return 'Service initial metadata received after service completion!'
+ if not implementation.metadata_transmitted(
+ state.service_initial_metadata_in_flight, initial_metadata):
+ return 'Service initial metadata maltransmitted: %s, %s' % (
+ state.service_initial_metadata_in_flight, initial_metadata)
+ else:
+ state.service_initial_metadata_in_flight = None
+ state.service_initial_metadata_received = True
+
+ if payload is not None:
+ if state.service_completion_received:
+ return 'Service payload received after service completion!'
+ elif not state.service_payloads_in_flight:
+ return 'Service payload "%s" received but not in flight!' % (payload,)
+ elif state.service_payloads_in_flight[0] != payload:
+ return 'Service payload mismatch: %s, %s' % (
+ state.invocation_payloads_in_flight[0], payload)
+ elif state.invocation_side_service_allowance < 1:
+ return 'Disallowed service payload!'
+ else:
+ state.service_payloads_in_flight.pop(0)
+ state.service_payloads_received += 1
+ state.invocation_side_service_allowance -= 1
+
+ if completion is not None:
+ if state.service_completion_received:
+ return 'Later service completion received: %s' % (completion,)
+ elif not implementation.completion_transmitted(
+ state.service_completion_in_flight, completion):
+ return 'Service completion maltransmitted: %s, %s' % (
+ state.service_completion_in_flight, completion)
+ else:
+ state.service_completion_in_flight = None
+ state.service_completion_received = True
+
+ if allowance is not None:
+ if allowance <= 0:
+ return 'Illegal allowance value: %s' % (allowance,)
+ else:
+ state.invocation_allowance_in_flight -= allowance
+ state.invocation_side_service_allowance += allowance
+
+
+class Invocation(
+ collections.namedtuple(
+ 'Invocation',
+ ('group', 'method', 'subscription_kind', 'timeout', 'initial_metadata',
+ 'payload', 'completion',))):
+ """A description of operation invocation.
+
+ Attributes:
+ group: The group identifier for the operation.
+ method: The method identifier for the operation.
+ subscription_kind: A base.Subscription.Kind value describing the kind of
+ subscription to use for the operation.
+ timeout: A duration in seconds to pass as the timeout value for the
+ operation.
+ initial_metadata: An object to pass as the initial metadata for the
+ operation or None.
+ payload: An object to pass as a payload value for the operation or None.
+ completion: An object to pass as a completion value for the operation or
+ None.
+ """
+
+
+class OnAdvance(
+ collections.namedtuple(
+ 'OnAdvance',
+ ('kind', 'initial_metadata', 'payload', 'completion', 'allowance'))):
+ """Describes action to be taken in a test in response to an advance call.
+
+ Attributes:
+ kind: A Kind value describing the overall kind of response.
+ initial_metadata: An initial metadata value to pass to a call of the advance
+ method of the operator under test. Only valid if kind is Kind.ADVANCE and
+ may be None.
+ payload: A payload value to pass to a call of the advance method of the
+ operator under test. Only valid if kind is Kind.ADVANCE and may be None.
+ completion: A base.Completion value to pass to a call of the advance method
+ of the operator under test. Only valid if kind is Kind.ADVANCE and may be
+ None.
+ allowance: An allowance value to pass to a call of the advance method of the
+ operator under test. Only valid if kind is Kind.ADVANCE and may be None.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ ADVANCE = 'advance'
+ DEFECT = 'defect'
+ IDLE = 'idle'
+
+
+_DEFECT_ON_ADVANCE = OnAdvance(OnAdvance.Kind.DEFECT, None, None, None, None)
+_IDLE_ON_ADVANCE = OnAdvance(OnAdvance.Kind.IDLE, None, None, None, None)
+
+
+class Instruction(
+ collections.namedtuple(
+ 'Instruction',
+ ('kind', 'advance_args', 'advance_kwargs', 'conclude_success',
+ 'conclude_message', 'conclude_invocation_outcome',
+ 'conclude_service_outcome',))):
+ """"""
+
+ @enum.unique
+ class Kind(enum.Enum):
+ ADVANCE = 'ADVANCE'
+ CANCEL = 'CANCEL'
+ CONCLUDE = 'CONCLUDE'
+
+
+class Controller(object):
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def failed(self, message):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def serialize_request(self, request):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def deserialize_request(self, serialized_request):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def serialize_response(self, response):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def deserialize_response(self, serialized_response):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def invocation(self):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def poll(self):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def on_service_advance(
+ self, initial_metadata, payload, completion, allowance):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def on_invocation_advance(
+ self, initial_metadata, payload, completion, allowance):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_on_termination(self, outcome):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def invocation_on_termination(self, outcome):
+ """"""
+ raise NotImplementedError()
+
+
+class ControllerCreator(object):
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def name(self):
+ """"""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def controller(self, implementation, randomness):
+ """"""
+ raise NotImplementedError()
+
+
+class _Remainder(
+ collections.namedtuple(
+ '_Remainder',
+ ('invocation_payloads', 'service_payloads', 'invocation_completion',
+ 'service_completion',))):
+ """Describes work remaining to be done in a portion of a test.
+
+ Attributes:
+ invocation_payloads: The number of payloads to be sent from the invocation
+ side of the operation to the service side of the operation.
+ service_payloads: The number of payloads to be sent from the service side of
+ the operation to the invocation side of the operation.
+ invocation_completion: Whether or not completion from the invocation side of
+ the operation should be indicated and has yet to be indicated.
+ service_completion: Whether or not completion from the service side of the
+ operation should be indicated and has yet to be indicated.
+ """
+
+
+class _SequenceController(Controller):
+
+ def __init__(self, sequence, implementation, randomness):
+ """Constructor.
+
+ Args:
+ sequence: A _sequence.Sequence describing the steps to be taken in the
+ test at a relatively high level.
+ implementation: A test_interfaces.Implementation encapsulating the
+ base interface implementation that is the system under test.
+ randomness: A random.Random instance for use in the test.
+ """
+ self._condition = threading.Condition()
+ self._sequence = sequence
+ self._implementation = implementation
+ self._randomness = randomness
+
+ self._until = None
+ self._remaining_elements = None
+ self._poll_next = None
+ self._message = None
+
+ self._state = _state.OperationState()
+ self._todo = None
+
+ # called with self._condition
+ def _failed(self, message):
+ self._message = message
+ self._condition.notify_all()
+
+ def _passed(self, invocation_outcome, service_outcome):
+ self._poll_next = Instruction(
+ Instruction.Kind.CONCLUDE, None, None, True, None, invocation_outcome,
+ service_outcome)
+ self._condition.notify_all()
+
+ def failed(self, message):
+ with self._condition:
+ self._failed(message)
+
+ def serialize_request(self, request):
+ return request + request
+
+ def deserialize_request(self, serialized_request):
+ return serialized_request[:len(serialized_request) / 2]
+
+ def serialize_response(self, response):
+ return response * 3
+
+ def deserialize_response(self, serialized_response):
+ return serialized_response[2 * len(serialized_response) / 3:]
+
+ def invocation(self):
+ with self._condition:
+ self._until = time.time() + self._sequence.maximum_duration
+ self._remaining_elements = list(self._sequence.elements)
+ if self._sequence.invocation.initial_metadata:
+ initial_metadata = self._implementation.invocation_initial_metadata()
+ self._state.invocation_initial_metadata_in_flight = initial_metadata
+ else:
+ initial_metadata = None
+ if self._sequence.invocation.payload:
+ payload = _create_payload(self._randomness)
+ self._state.invocation_payloads_in_flight.append(payload)
+ else:
+ payload = None
+ if self._sequence.invocation.complete:
+ completion = self._implementation.invocation_completion()
+ self._state.invocation_completion_in_flight = completion
+ else:
+ completion = None
+ return Invocation(
+ _GROUP, _METHOD, base.Subscription.Kind.FULL,
+ self._sequence.invocation.timeout, initial_metadata, payload,
+ completion)
+
+ def poll(self):
+ with self._condition:
+ while True:
+ if self._message is not None:
+ return Instruction(
+ Instruction.Kind.CONCLUDE, None, None, False, self._message, None,
+ None)
+ elif self._poll_next:
+ poll_next = self._poll_next
+ self._poll_next = None
+ return poll_next
+ elif self._until < time.time():
+ return Instruction(
+ Instruction.Kind.CONCLUDE, None, None, False,
+ 'overran allotted time!', None, None)
+ else:
+ self._condition.wait(timeout=self._until-time.time())
+
+ def on_service_advance(
+ self, initial_metadata, payload, completion, allowance):
+ with self._condition:
+ message = _verify_service_advance_and_update_state(
+ initial_metadata, payload, completion, allowance, self._state,
+ self._implementation)
+ if message is not None:
+ self._failed(message)
+ if self._todo is not None:
+ raise ValueError('TODO!!!')
+ elif _anything_in_flight(self._state):
+ return _IDLE_ON_ADVANCE
+ elif self._remaining_elements:
+ element = self._remaining_elements.pop(0)
+ if element.kind is _sequence.Element.Kind.SERVICE_TRANSMISSION:
+ if element.transmission.initial_metadata:
+ initial_metadata = self._implementation.service_initial_metadata()
+ self._state.service_initial_metadata_in_flight = initial_metadata
+ else:
+ initial_metadata = None
+ if element.transmission.payload:
+ payload = _create_payload(self._randomness)
+ self._state.service_payloads_in_flight.append(payload)
+ self._state.service_side_service_allowance -= 1
+ else:
+ payload = None
+ if element.transmission.complete:
+ completion = self._implementation.service_completion()
+ self._state.service_completion_in_flight = completion
+ else:
+ completion = None
+ if (not self._state.invocation_completion_received and
+ 0 <= self._state.service_side_invocation_allowance):
+ allowance = 1
+ self._state.service_side_invocation_allowance += 1
+ self._state.invocation_allowance_in_flight += 1
+ else:
+ allowance = None
+ return OnAdvance(
+ OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion,
+ allowance)
+ else:
+ raise ValueError('TODO!!!')
+ else:
+ return _IDLE_ON_ADVANCE
+
+ def on_invocation_advance(
+ self, initial_metadata, payload, completion, allowance):
+ with self._condition:
+ message = _verify_invocation_advance_and_update_state(
+ initial_metadata, payload, completion, allowance, self._state,
+ self._implementation)
+ if message is not None:
+ self._failed(message)
+ if self._todo is not None:
+ raise ValueError('TODO!!!')
+ elif _anything_in_flight(self._state):
+ return _IDLE_ON_ADVANCE
+ elif self._remaining_elements:
+ element = self._remaining_elements.pop(0)
+ if element.kind is _sequence.Element.Kind.INVOCATION_TRANSMISSION:
+ if element.transmission.initial_metadata:
+ initial_metadata = self._implementation.invocation_initial_metadata()
+ self._state.invocation_initial_metadata_in_fight = initial_metadata
+ else:
+ initial_metadata = None
+ if element.transmission.payload:
+ payload = _create_payload(self._randomness)
+ self._state.invocation_payloads_in_flight.append(payload)
+ self._state.invocation_side_invocation_allowance -= 1
+ else:
+ payload = None
+ if element.transmission.complete:
+ completion = self._implementation.invocation_completion()
+ self._state.invocation_completion_in_flight = completion
+ else:
+ completion = None
+ if (not self._state.service_completion_received and
+ 0 <= self._state.invocation_side_service_allowance):
+ allowance = 1
+ self._state.invocation_side_service_allowance += 1
+ self._state.service_allowance_in_flight += 1
+ else:
+ allowance = None
+ return OnAdvance(
+ OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion,
+ allowance)
+ else:
+ raise ValueError('TODO!!!')
+ else:
+ return _IDLE_ON_ADVANCE
+
+ def service_on_termination(self, outcome):
+ with self._condition:
+ self._state.service_side_outcome = outcome
+ if self._todo is not None or self._remaining_elements:
+ self._failed('Premature service-side outcome %s!' % (outcome,))
+ elif outcome is not self._sequence.outcome.service:
+ self._failed(
+ 'Incorrect service-side outcome: %s should have been %s' % (
+ outcome, self._sequence.outcome.service))
+ elif self._state.invocation_side_outcome is not None:
+ self._passed(self._state.invocation_side_outcome, outcome)
+
+ def invocation_on_termination(self, outcome):
+ with self._condition:
+ self._state.invocation_side_outcome = outcome
+ if self._todo is not None or self._remaining_elements:
+ self._failed('Premature invocation-side outcome %s!' % (outcome,))
+ elif outcome is not self._sequence.outcome.invocation:
+ self._failed(
+ 'Incorrect invocation-side outcome: %s should have been %s' % (
+ outcome, self._sequence.outcome.invocation))
+ elif self._state.service_side_outcome is not None:
+ self._passed(outcome, self._state.service_side_outcome)
+
+
+class _SequenceControllerCreator(ControllerCreator):
+
+ def __init__(self, sequence):
+ self._sequence = sequence
+
+ def name(self):
+ return self._sequence.name
+
+ def controller(self, implementation, randomness):
+ return _SequenceController(self._sequence, implementation, randomness)
+
+
+CONTROLLER_CREATORS = tuple(
+ _SequenceControllerCreator(sequence) for sequence in _sequence.SEQUENCES)
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
new file mode 100644
index 0000000000..1d77aaebe6
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
@@ -0,0 +1,168 @@
+# 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.
+
+"""Part of the tests of the base interface of RPC Framework."""
+
+import collections
+import enum
+
+from grpc.framework.interfaces.base import base
+from grpc_test.framework.common import test_constants
+
+
+class Invocation(
+ collections.namedtuple(
+ 'Invocation', ('timeout', 'initial_metadata', 'payload', 'complete',))):
+ """A recipe for operation invocation.
+
+ Attributes:
+ timeout: A duration in seconds to pass to the system under test as the
+ operation's timeout value.
+ initial_metadata: A boolean indicating whether or not to pass initial
+ metadata when invoking the operation.
+ payload: A boolean indicating whether or not to pass a payload when
+ invoking the operation.
+ complete: A boolean indicating whether or not to indicate completion of
+ transmissions from the invoking side of the operation when invoking the
+ operation.
+ """
+
+
+class Transmission(
+ collections.namedtuple(
+ 'Transmission', ('initial_metadata', 'payload', 'complete',))):
+ """A recipe for a single transmission in an operation.
+
+ Attributes:
+ initial_metadata: A boolean indicating whether or not to pass initial
+ metadata as part of the transmission.
+ payload: A boolean indicating whether or not to pass a payload as part of
+ the transmission.
+ complete: A boolean indicating whether or not to indicate completion of
+ transmission from the transmitting side of the operation as part of the
+ transmission.
+ """
+
+
+class Intertransmission(
+ collections.namedtuple('Intertransmission', ('invocation', 'service',))):
+ """A recipe for multiple transmissions in an operation.
+
+ Attributes:
+ invocation: An integer describing the number of payloads to send from the
+ invocation side of the operation to the service side.
+ service: An integer describing the number of payloads to send from the
+ service side of the operation to the invocation side.
+ """
+
+
+class Element(collections.namedtuple('Element', ('kind', 'transmission',))):
+ """A sum type for steps to perform when testing an operation.
+
+ Attributes:
+ kind: A Kind value describing the kind of step to perform in the test.
+ transmission: Only valid for kinds Kind.INVOCATION_TRANSMISSION and
+ Kind.SERVICE_TRANSMISSION, a Transmission value describing the details of
+ the transmission to be made.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ INVOCATION_TRANSMISSION = 'invocation transmission'
+ SERVICE_TRANSMISSION = 'service transmission'
+ INTERTRANSMISSION = 'intertransmission'
+ INVOCATION_CANCEL = 'invocation cancel'
+ SERVICE_CANCEL = 'service cancel'
+ INVOCATION_FAILURE = 'invocation failure'
+ SERVICE_FAILURE = 'service failure'
+
+
+class Outcome(collections.namedtuple('Outcome', ('invocation', 'service',))):
+ """A description of the expected outcome of an operation test.
+
+ Attributes:
+ invocation: The base.Outcome value expected on the invocation side of the
+ operation.
+ service: The base.Outcome value expected on the service side of the
+ operation.
+ """
+
+
+class Sequence(
+ collections.namedtuple(
+ 'Sequence',
+ ('name', 'maximum_duration', 'invocation', 'elements', 'outcome',))):
+ """Describes at a high level steps to perform in a test.
+
+ Attributes:
+ name: The string name of the sequence.
+ maximum_duration: A length of time in seconds to allow for the test before
+ declaring it to have failed.
+ invocation: An Invocation value describing how to invoke the operation
+ under test.
+ elements: A sequence of Element values describing at coarse granularity
+ actions to take during the operation under test.
+ outcome: An Outcome value describing the expected outcome of the test.
+ """
+
+_EASY = Sequence(
+ 'Easy',
+ test_constants.TIME_ALLOWANCE,
+ Invocation(test_constants.LONG_TIMEOUT, True, True, True),
+ (
+ Element(
+ Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, True)),
+ ),
+ Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED))
+
+_PEASY = Sequence(
+ 'Peasy',
+ test_constants.TIME_ALLOWANCE,
+ Invocation(test_constants.LONG_TIMEOUT, True, True, False),
+ (
+ Element(
+ Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, False)),
+ Element(
+ Element.Kind.INVOCATION_TRANSMISSION,
+ Transmission(False, True, True)),
+ Element(
+ Element.Kind.SERVICE_TRANSMISSION, Transmission(False, True, True)),
+ ),
+ Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED))
+
+
+# TODO(issue 2959): Finish this test suite. This tuple of sequences should
+# contain at least the values in the Cartesian product of (half-duplex,
+# full-duplex) * (zero payloads, one payload, test_constants.STREAM_LENGTH
+# payloads) * (completion, cancellation, expiration, programming defect in
+# servicer code).
+SEQUENCES = (
+ _EASY,
+ _PEASY,
+)
diff --git a/src/ruby/bin/interop/test/cpp/interop/test_services.rb b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py
index 5a3146c581..21cf33aeb6 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test_services.rb
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py
@@ -27,34 +27,29 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# Source: test/cpp/interop/test.proto for package 'grpc.testing'
-
-require 'grpc'
-require 'test/cpp/interop/test'
-
-module Grpc
- module Testing
- module TestService
-
- # TODO: add proto service documentation here
- class Service
-
- include GRPC::GenericService
-
- self.marshal_class_method = :encode
- self.unmarshal_class_method = :decode
- self.service_name = 'grpc.testing.TestService'
-
- rpc :EmptyCall, Empty, Empty
- rpc :UnaryCall, SimpleRequest, SimpleResponse
- rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
- rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
- rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
- rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
- end
-
- Stub = Service.rpc_stub_class
- end
- end
-end
+"""Part of the tests of the base interface of RPC Framework."""
+
+
+class OperationState(object):
+
+ def __init__(self):
+ self.invocation_initial_metadata_in_flight = None
+ self.invocation_initial_metadata_received = False
+ self.invocation_payloads_in_flight = []
+ self.invocation_payloads_received = 0
+ self.invocation_completion_in_flight = None
+ self.invocation_completion_received = False
+ self.service_initial_metadata_in_flight = None
+ self.service_initial_metadata_received = False
+ self.service_payloads_in_flight = []
+ self.service_payloads_received = 0
+ self.service_completion_in_flight = None
+ self.service_completion_received = False
+ self.invocation_side_invocation_allowance = 1
+ self.invocation_side_service_allowance = 1
+ self.service_side_invocation_allowance = 1
+ self.service_side_service_allowance = 1
+ self.invocation_allowance_in_flight = 0
+ self.service_allowance_in_flight = 0
+ self.invocation_side_outcome = None
+ self.service_side_outcome = None
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
new file mode 100644
index 0000000000..dd332fe5dd
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
@@ -0,0 +1,260 @@
+# 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.
+
+"""Tests of the base interface of RPC Framework."""
+
+import logging
+import random
+import threading
+import time
+import unittest
+
+from grpc.framework.foundation import logging_pool
+from grpc.framework.interfaces.base import base
+from grpc.framework.interfaces.base import utilities
+from grpc_test.framework.common import test_constants
+from grpc_test.framework.interfaces.base import _control
+from grpc_test.framework.interfaces.base import test_interfaces
+
+_SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True))
+
+_EMPTY_OUTCOME_DICT = {outcome: 0 for outcome in base.Outcome}
+
+
+class _Serialization(test_interfaces.Serialization):
+
+ def serialize_request(self, request):
+ return request + request
+
+ def deserialize_request(self, serialized_request):
+ return serialized_request[:len(serialized_request) / 2]
+
+ def serialize_response(self, response):
+ return response * 3
+
+ def deserialize_response(self, serialized_response):
+ return serialized_response[2 * len(serialized_response) / 3:]
+
+
+def _advance(quadruples, operator, controller):
+ try:
+ for quadruple in quadruples:
+ operator.advance(
+ initial_metadata=quadruple[0], payload=quadruple[1],
+ completion=quadruple[2], allowance=quadruple[3])
+ except Exception as e: # pylint: disable=broad-except
+ controller.failed('Exception on advance: %e' % e)
+
+
+class _Operator(base.Operator):
+
+ def __init__(self, controller, on_advance, pool, operator_under_test):
+ self._condition = threading.Condition()
+ self._controller = controller
+ self._on_advance = on_advance
+ self._pool = pool
+ self._operator_under_test = operator_under_test
+ self._pending_advances = []
+
+ def set_operator_under_test(self, operator_under_test):
+ with self._condition:
+ self._operator_under_test = operator_under_test
+ pent_advances = self._pending_advances
+ self._pending_advances = []
+ pool = self._pool
+ controller = self._controller
+
+ if pool is None:
+ _advance(pent_advances, operator_under_test, controller)
+ else:
+ pool.submit(_advance, pent_advances, operator_under_test, controller)
+
+ def advance(
+ self, initial_metadata=None, payload=None, completion=None,
+ allowance=None):
+ on_advance = self._on_advance(
+ initial_metadata, payload, completion, allowance)
+ if on_advance.kind is _control.OnAdvance.Kind.ADVANCE:
+ with self._condition:
+ pool = self._pool
+ operator_under_test = self._operator_under_test
+ controller = self._controller
+
+ quadruple = (
+ on_advance.initial_metadata, on_advance.payload,
+ on_advance.completion, on_advance.allowance)
+ if pool is None:
+ _advance((quadruple,), operator_under_test, controller)
+ else:
+ pool.submit(_advance, (quadruple,), operator_under_test, controller)
+ elif on_advance.kind is _control.OnAdvance.Kind.DEFECT:
+ raise ValueError(
+ 'Deliberately raised exception from Operator.advance (in a test)!')
+
+
+class _Servicer(base.Servicer):
+ """An base.Servicer with instrumented for testing."""
+
+ def __init__(self, group, method, controllers, pool):
+ self._condition = threading.Condition()
+ self._group = group
+ self._method = method
+ self._pool = pool
+ self._controllers = list(controllers)
+
+ def service(self, group, method, context, output_operator):
+ with self._condition:
+ controller = self._controllers.pop(0)
+ if group != self._group or method != self._method:
+ controller.fail(
+ '%s != %s or %s != %s' % (group, self._group, method, self._method))
+ raise base.NoSuchMethodError()
+ else:
+ operator = _Operator(
+ controller, controller.on_service_advance, self._pool,
+ output_operator)
+ outcome = context.add_termination_callback(
+ controller.service_on_termination)
+ if outcome is not None:
+ controller.service_on_termination(outcome)
+ return utilities.full_subscription(operator)
+
+
+class _OperationTest(unittest.TestCase):
+
+ def setUp(self):
+ if self._synchronicity_variation:
+ self._pool = logging_pool.pool(test_constants.POOL_SIZE)
+ else:
+ self._pool = None
+ self._controller = self._controller_creator.controller(
+ self._implementation, self._randomness)
+
+ def tearDown(self):
+ if self._synchronicity_variation:
+ self._pool.shutdown(wait=True)
+ else:
+ self._pool = None
+
+ def test_operation(self):
+ invocation = self._controller.invocation()
+ if invocation.subscription_kind is base.Subscription.Kind.FULL:
+ test_operator = _Operator(
+ self._controller, self._controller.on_invocation_advance,
+ self._pool, None)
+ subscription = utilities.full_subscription(test_operator)
+ else:
+ # TODO(nathaniel): support and test other subscription kinds.
+ self.fail('Non-full subscriptions not yet supported!')
+
+ servicer = _Servicer(
+ invocation.group, invocation.method, (self._controller,), self._pool)
+
+ invocation_end, service_end, memo = self._implementation.instantiate(
+ {(invocation.group, invocation.method): _Serialization()}, servicer)
+
+ try:
+ invocation_end.start()
+ service_end.start()
+ operation_context, operator_under_test = invocation_end.operate(
+ invocation.group, invocation.method, subscription, invocation.timeout,
+ initial_metadata=invocation.initial_metadata, payload=invocation.payload,
+ completion=invocation.completion)
+ test_operator.set_operator_under_test(operator_under_test)
+ outcome = operation_context.add_termination_callback(
+ self._controller.invocation_on_termination)
+ if outcome is not None:
+ self._controller.invocation_on_termination(outcome)
+ except Exception as e: # pylint: disable=broad-except
+ self._controller.failed('Exception on invocation: %s' % e)
+ self.fail(e)
+
+ while True:
+ instruction = self._controller.poll()
+ if instruction.kind is _control.Instruction.Kind.ADVANCE:
+ try:
+ test_operator.advance(
+ *instruction.advance_args, **instruction.advance_kwargs)
+ except Exception as e: # pylint: disable=broad-except
+ self._controller.failed('Exception on instructed advance: %s' % e)
+ elif instruction.kind is _control.Instruction.Kind.CANCEL:
+ try:
+ operation_context.cancel()
+ except Exception as e: # pylint: disable=broad-except
+ self._controller.failed('Exception on cancel: %s' % e)
+ elif instruction.kind is _control.Instruction.Kind.CONCLUDE:
+ break
+
+ invocation_end.stop_gracefully()
+ service_end.stop_gracefully()
+ invocation_stats = invocation_end.operation_stats()
+ service_stats = service_end.operation_stats()
+
+ self._implementation.destantiate(memo)
+
+ self.assertTrue(
+ instruction.conclude_success, msg=instruction.conclude_message)
+
+ expected_invocation_stats = dict(_EMPTY_OUTCOME_DICT)
+ expected_invocation_stats[instruction.conclude_invocation_outcome] += 1
+ self.assertDictEqual(expected_invocation_stats, invocation_stats)
+ expected_service_stats = dict(_EMPTY_OUTCOME_DICT)
+ expected_service_stats[instruction.conclude_service_outcome] += 1
+ self.assertDictEqual(expected_service_stats, service_stats)
+
+
+def test_cases(implementation):
+ """Creates unittest.TestCase classes for a given Base implementation.
+
+ Args:
+ implementation: A test_interfaces.Implementation specifying creation and
+ destruction of the Base implementation under test.
+
+ Returns:
+ A sequence of subclasses of unittest.TestCase defining tests of the
+ specified Base layer implementation.
+ """
+ random_seed = hash(time.time())
+ logging.warning('Random seed for this execution: %s', random_seed)
+ randomness = random.Random(x=random_seed)
+
+ test_case_classes = []
+ for synchronicity_variation in _SYNCHRONICITY_VARIATION:
+ for controller_creator in _control.CONTROLLER_CREATORS:
+ name = ''.join(
+ (synchronicity_variation[0], controller_creator.name(), 'Test',))
+ test_case_classes.append(
+ type(name, (_OperationTest,),
+ {'_implementation': implementation,
+ '_randomness': randomness,
+ '_synchronicity_variation': synchronicity_variation[1],
+ '_controller_creator': controller_creator,
+ }))
+
+ return test_case_classes
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py
new file mode 100644
index 0000000000..02426ab846
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py
@@ -0,0 +1,186 @@
+# 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.
+
+"""Interfaces used in tests of implementations of the Base layer."""
+
+import abc
+
+from grpc.framework.interfaces.base import base # pylint: disable=unused-import
+
+
+class Serialization(object):
+ """Specifies serialization and deserialization of test payloads."""
+ __metaclass__ = abc.ABCMeta
+
+ def serialize_request(self, request):
+ """Serializes a request value used in a test.
+
+ Args:
+ request: A request value created by a test.
+
+ Returns:
+ A bytestring that is the serialization of the given request.
+ """
+ raise NotImplementedError()
+
+ def deserialize_request(self, serialized_request):
+ """Deserializes a request value used in a test.
+
+ Args:
+ serialized_request: A bytestring that is the serialization of some request
+ used in a test.
+
+ Returns:
+ The request value encoded by the given bytestring.
+ """
+ raise NotImplementedError()
+
+ def serialize_response(self, response):
+ """Serializes a response value used in a test.
+
+ Args:
+ response: A response value created by a test.
+
+ Returns:
+ A bytestring that is the serialization of the given response.
+ """
+ raise NotImplementedError()
+
+ def deserialize_response(self, serialized_response):
+ """Deserializes a response value used in a test.
+
+ Args:
+ serialized_response: A bytestring that is the serialization of some
+ response used in a test.
+
+ Returns:
+ The response value encoded by the given bytestring.
+ """
+ raise NotImplementedError()
+
+
+class Implementation(object):
+ """Specifies an implementation of the Base layer."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def instantiate(self, serializations, servicer):
+ """Instantiates the Base layer implementation to be used in a test.
+
+ Args:
+ serializations: A dict from group-method pair to Serialization object
+ specifying how to serialize and deserialize payload values used in the
+ test.
+ servicer: A base.Servicer object to be called to service RPCs made during
+ the test.
+
+ Returns:
+ A sequence of length three the first element of which is a
+ base.End to be used to invoke RPCs, the second element of which is a
+ base.End to be used to service invoked RPCs, and the third element of
+ which is an arbitrary memo object to be kept and passed to destantiate
+ at the conclusion of the test.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def destantiate(self, memo):
+ """Destroys the Base layer implementation under test.
+
+ Args:
+ memo: The object from the third position of the return value of a call to
+ instantiate.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def invocation_initial_metadata(self):
+ """Provides an operation's invocation-side initial metadata.
+
+ Returns:
+ A value to use for an operation's invocation-side initial metadata, or
+ None.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_initial_metadata(self):
+ """Provices an operation's service-side initial metadata.
+
+ Returns:
+ A value to use for an operation's service-side initial metadata, or
+ None.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def invocation_completion(self):
+ """Provides an operation's invocation-side completion.
+
+ Returns:
+ A base.Completion to use for an operation's invocation-side completion.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_completion(self):
+ """Provides an operation's service-side completion.
+
+ Returns:
+ A base.Completion to use for an operation's service-side completion.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def metadata_transmitted(self, original_metadata, transmitted_metadata):
+ """Identifies whether or not metadata was properly transmitted.
+
+ Args:
+ original_metadata: A metadata value passed to the system under test.
+ transmitted_metadata: The same metadata value after having been
+ transmitted through the system under test.
+
+ Returns:
+ Whether or not the metadata was properly transmitted.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def completion_transmitted(self, original_completion, transmitted_completion):
+ """Identifies whether or not a base.Completion was properly transmitted.
+
+ Args:
+ original_completion: A base.Completion passed to the system under test.
+ transmitted_completion: The same completion value after having been
+ transmitted through the system under test.
+
+ Returns:
+ Whether or not the completion was properly transmitted.
+ """
+ raise NotImplementedError()
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
index 26ca035c44..1e575d1a9e 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
@@ -303,16 +303,9 @@ class TransmissionTest(object):
invocation_message, links.Ticket.Termination.COMPLETION)
self._invocation_link.accept_ticket(original_invocation_ticket)
- # TODO(nathaniel): This shouldn't be necessary. Detecting the end of the
- # invocation-side ticket sequence shouldn't require granting allowance for
- # another payload.
self._service_mate.block_until_tickets_satisfy(
at_least_n_payloads_received_predicate(1))
service_operation_id = self._service_mate.tickets()[0].operation_id
- self._service_link.accept_ticket(
- links.Ticket(
- service_operation_id, 0, None, None, links.Ticket.Subscription.FULL,
- None, 1, None, None, None, None, None, None))
self._service_mate.block_until_tickets_satisfy(terminated)
self._assert_is_valid_invocation_sequence(
@@ -321,7 +314,7 @@ class TransmissionTest(object):
invocation_terminal_metadata, links.Ticket.Termination.COMPLETION)
original_service_ticket = links.Ticket(
- service_operation_id, 1, None, None, links.Ticket.Subscription.FULL,
+ service_operation_id, 0, None, None, links.Ticket.Subscription.FULL,
timeout, 0, service_initial_metadata, service_payload,
service_terminal_metadata, service_code, service_message,
links.Ticket.Termination.COMPLETION)
diff --git a/src/ruby/.rspec b/src/ruby/.rspec
index cd7c5fb5b2..2320752db4 100755
--- a/src/ruby/.rspec
+++ b/src/ruby/.rspec
@@ -1,4 +1,5 @@
-I.
+-Ipb
--require spec_helper
--format documentation
--color
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index 47e382afa7..312bdca384 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -5,6 +5,7 @@ inherit_from: .rubocop_todo.yml
AllCops:
Exclude:
- 'bin/apis/**/*'
- - 'bin/interop/test/**/*'
- 'bin/math.rb'
- 'bin/math_services.rb'
+ - 'pb/grpc/health/v1alpha/*'
+ - 'pb/test/**/*'
diff --git a/src/ruby/README.md b/src/ruby/README.md
index 4b657c0bd4..f8902e34c5 100644
--- a/src/ruby/README.md
+++ b/src/ruby/README.md
@@ -12,12 +12,36 @@ PREREQUISITES
-------------
- Ruby 2.x. The gRPC API uses keyword args.
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core.
INSTALLATION
---------------
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Ruby.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC Ruby package
+
+```sh
+gem install grpc
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Ruby.
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s ruby
```
@@ -26,12 +50,6 @@ This will download and run the [gRPC install script][], then install the latest
BUILD FROM SOURCE
---------------------
- Clone this repository
-- Build the gRPC C core
-E.g, from the root of the gRPC [Git repository](https://github.com/google/grpc)
-```sh
-$ cd ../..
-$ make && sudo make install
-```
- Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling
the exact ruby version that's used.
@@ -77,8 +95,8 @@ Directory structure is the layout for [ruby extensions][]
GRPC.logger.info("Answer: #{resp.inspect}")
```
[homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[ruby extensions]:http://guides.rubygems.org/gems-with-extensions/
[rubydoc]: http://www.rubydoc.info/gems/grpc
[grpc.io]: http://www.grpc.io/docs/installation/ruby.html
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index 02af9a84b8..cc7832b12d 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -20,7 +20,8 @@ SPEC_SUITES = [
{ id: :bidi, title: 'bidi tests', dir: %w(spec/generic),
tag: 'bidi' },
{ id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
- tag: 'server' }
+ tag: 'server' },
+ { id: :pb, title: 'protobuf service tests', dir: %w(spec/pb) }
]
namespace :suite do
SPEC_SUITES.each do |suite|
@@ -50,7 +51,8 @@ task 'suite:wrapper' => [:compile, :rubocop]
task 'suite:idiomatic' => 'suite:wrapper'
task 'suite:bidi' => 'suite:wrapper'
task 'suite:server' => 'suite:wrapper'
+task 'suite:pb' => 'suite:server'
desc 'Compiles the gRPC extension then runs all the tests'
-task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
+task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server']
task default: :all
diff --git a/src/ruby/bin/grpc_ruby_interop_client b/src/ruby/bin/grpc_ruby_interop_client
new file mode 100755
index 0000000000..e79fd33aa5
--- /dev/null
+++ b/src/ruby/bin/grpc_ruby_interop_client
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+# Provides a gem binary entry point for the interop client.
+require 'test/client'
diff --git a/src/ruby/bin/grpc_ruby_interop_server b/src/ruby/bin/grpc_ruby_interop_server
new file mode 100755
index 0000000000..656a5f7c99
--- /dev/null
+++ b/src/ruby/bin/grpc_ruby_interop_server
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+# Provides a gem binary entry point for the interop server
+require 'test/server'
diff --git a/src/ruby/bin/interop/README.md b/src/ruby/bin/interop/README.md
deleted file mode 100644
index 84fc663620..0000000000
--- a/src/ruby/bin/interop/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Interop test protos
-===================
-
-These ruby classes were generated with protoc v3, using grpc's ruby compiler
-plugin.
-
-- As of 2015/01 protoc v3 is available in the
-[google-protobuf](https://github.com/google/protobuf) repo
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index da4caa842b..239083f37f 100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -29,6 +29,12 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# #######################################################################
+# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb
+#
+# This file remains to support existing tools and scripts that use it.
+# ######################################################################
+#
# interop_client is a testing tool that accesses a gRPC interop testing
# server and runs a test on it.
#
@@ -39,339 +45,7 @@
# --test_case=<testcase_name>
this_dir = File.expand_path(File.dirname(__FILE__))
-lib_dir = File.join(File.dirname(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 'optparse'
-require 'minitest'
-require 'minitest/assertions'
-
-require 'grpc'
-require 'googleauth'
-require 'google/protobuf'
-
-require 'test/cpp/interop/test_services'
-require 'test/cpp/interop/messages'
-require 'test/cpp/interop/empty'
-
-require 'signet/ssl_config'
-
-AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
-
-# loads the certificates used to access the test server securely.
-def load_test_certs
- this_dir = File.expand_path(File.dirname(__FILE__))
- data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
- files = ['ca.pem', 'server1.key', 'server1.pem']
- files.map { |f| File.open(File.join(data_dir, f)).read }
-end
-
-# loads the certificates used to access the test server securely.
-def load_prod_cert
- fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
- GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
- File.open(ENV['SSL_CERT_FILE']).read
-end
-
-# creates SSL Credentials from the test certificates.
-def test_creds
- certs = load_test_certs
- GRPC::Core::Credentials.new(certs[0])
-end
-
-# creates SSL Credentials from the production certificates.
-def prod_creds
- cert_text = load_prod_cert
- GRPC::Core::Credentials.new(cert_text)
-end
-
-# creates the SSL Credentials.
-def ssl_creds(use_test_ca)
- return test_creds if use_test_ca
- prod_creds
-end
-
-# creates a test stub that accesses host:port securely.
-def create_stub(opts)
- address = "#{opts.host}:#{opts.port}"
- if opts.secure
- stub_opts = {
- :creds => ssl_creds(opts.use_test_ca),
- GRPC::Core::Channel::SSL_TARGET => opts.host_override
- }
-
- # Add service account creds if specified
- wants_creds = %w(all compute_engine_creds service_account_creds)
- if wants_creds.include?(opts.test_case)
- unless opts.oauth_scope.nil?
- auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
- stub_opts[:update_metadata] = auth_creds.updater_proc
- end
- end
-
- if opts.test_case == 'jwt_token_creds' # don't use a scope
- auth_creds = Google::Auth.get_application_default
- stub_opts[:update_metadata] = auth_creds.updater_proc
- end
-
- GRPC.logger.info("... connecting securely to #{address}")
- Grpc::Testing::TestService::Stub.new(address, **stub_opts)
- else
- GRPC.logger.info("... connecting insecurely to #{address}")
- Grpc::Testing::TestService::Stub.new(address)
- end
-end
-
-# produces a string of null chars (\0) of length l.
-def nulls(l)
- fail 'requires #{l} to be +ve' if l < 0
- [].pack('x' * l).force_encoding('utf-8')
-end
-
-# a PingPongPlayer implements the ping pong bidi test.
-class PingPongPlayer
- include Minitest::Assertions
- include Grpc::Testing
- include Grpc::Testing::PayloadType
- attr_accessor :assertions # required by Minitest::Assertions
- attr_accessor :queue
- attr_accessor :canceller_op
-
- # reqs is the enumerator over the requests
- def initialize(msg_sizes)
- @queue = Queue.new
- @msg_sizes = msg_sizes
- @assertions = 0 # required by Minitest::Assertions
- @canceller_op = nil # used to cancel after the first response
- end
-
- def each_item
- return enum_for(:each_item) unless block_given?
- req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short
- count = 0
- @msg_sizes.each do |m|
- req_size, resp_size = m
- req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
- response_type: :COMPRESSABLE,
- response_parameters: [p_cls.new(size: resp_size)])
- yield req
- resp = @queue.pop
- assert_equal(:COMPRESSABLE, resp.payload.type, 'payload type is wrong')
- assert_equal(resp_size, resp.payload.body.length,
- "payload body #{count} has the wrong length")
- p "OK: ping_pong #{count}"
- count += 1
- unless @canceller_op.nil?
- canceller_op.cancel
- break
- end
- end
- end
-end
-
-# defines methods corresponding to each interop test case.
-class NamedTests
- include Minitest::Assertions
- include Grpc::Testing
- include Grpc::Testing::PayloadType
- attr_accessor :assertions # required by Minitest::Assertions
-
- def initialize(stub, args)
- @assertions = 0 # required by Minitest::Assertions
- @stub = stub
- @args = args
- end
-
- def empty_unary
- resp = @stub.empty_call(Empty.new)
- assert resp.is_a?(Empty), 'empty_unary: invalid response'
- p 'OK: empty_unary'
- end
-
- def large_unary
- perform_large_unary
- p 'OK: large_unary'
- end
-
- def service_account_creds
- # ignore this test if the oauth options are not set
- if @args.oauth_scope.nil?
- p 'NOT RUN: service_account_creds; no service_account settings'
- return
- end
- json_key = File.read(ENV[AUTH_ENV])
- wanted_email = MultiJson.load(json_key)['client_email']
- resp = perform_large_unary(fill_username: true,
- fill_oauth_scope: true)
- assert_equal(wanted_email, resp.username,
- 'service_account_creds: incorrect username')
- assert(@args.oauth_scope.include?(resp.oauth_scope),
- 'service_account_creds: incorrect oauth_scope')
- p 'OK: service_account_creds'
- end
-
- def jwt_token_creds
- json_key = File.read(ENV[AUTH_ENV])
- wanted_email = MultiJson.load(json_key)['client_email']
- resp = perform_large_unary(fill_username: true)
- assert_equal(wanted_email, resp.username,
- 'service_account_creds: incorrect username')
- p 'OK: jwt_token_creds'
- end
-
- def compute_engine_creds
- resp = perform_large_unary(fill_username: true,
- fill_oauth_scope: true)
- assert_equal(@args.default_service_account, resp.username,
- 'compute_engine_creds: incorrect username')
- p 'OK: compute_engine_creds'
- end
-
- def client_streaming
- msg_sizes = [27_182, 8, 1828, 45_904]
- wanted_aggregate_size = 74_922
- reqs = msg_sizes.map do |x|
- req = Payload.new(body: nulls(x))
- StreamingInputCallRequest.new(payload: req)
- end
- resp = @stub.streaming_input_call(reqs)
- assert_equal(wanted_aggregate_size, resp.aggregated_payload_size,
- 'client_streaming: aggregate payload size is incorrect')
- p 'OK: client_streaming'
- end
-
- def server_streaming
- msg_sizes = [31_415, 9, 2653, 58_979]
- response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
- req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
- response_parameters: response_spec)
- resps = @stub.streaming_output_call(req)
- resps.each_with_index do |r, i|
- assert i < msg_sizes.length, 'too many responses'
- assert_equal(:COMPRESSABLE, r.payload.type,
- 'payload type is wrong')
- assert_equal(msg_sizes[i], r.payload.body.length,
- 'payload body #{i} has the wrong length')
- end
- p 'OK: server_streaming'
- end
-
- def ping_pong
- msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
- ppp = PingPongPlayer.new(msg_sizes)
- resps = @stub.full_duplex_call(ppp.each_item)
- resps.each { |r| ppp.queue.push(r) }
- p 'OK: ping_pong'
- end
-
- def cancel_after_begin
- msg_sizes = [27_182, 8, 1828, 45_904]
- reqs = msg_sizes.map do |x|
- req = Payload.new(body: nulls(x))
- StreamingInputCallRequest.new(payload: req)
- end
- op = @stub.streaming_input_call(reqs, return_op: true)
- op.cancel
- assert_raises(GRPC::Cancelled) { op.execute }
- assert(op.cancelled, 'call operation should be CANCELLED')
- p 'OK: cancel_after_begin'
- end
-
- def cancel_after_first_response
- msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
- ppp = PingPongPlayer.new(msg_sizes)
- op = @stub.full_duplex_call(ppp.each_item, return_op: true)
- ppp.canceller_op = op # causes ppp to cancel after the 1st message
- op.execute.each { |r| ppp.queue.push(r) }
- op.wait
- assert(op.cancelled, 'call operation was not CANCELLED')
- p 'OK: cancel_after_first_response'
- end
-
- def all
- all_methods = NamedTests.instance_methods(false).map(&:to_s)
- all_methods.each do |m|
- next if m == 'all' || m.start_with?('assert')
- p "TESTCASE: #{m}"
- method(m).call
- end
- end
-
- private
-
- def perform_large_unary(fill_username: false, fill_oauth_scope: false)
- req_size, wanted_response_size = 271_828, 314_159
- payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
- req = SimpleRequest.new(response_type: :COMPRESSABLE,
- response_size: wanted_response_size,
- payload: payload)
- req.fill_username = fill_username
- req.fill_oauth_scope = fill_oauth_scope
- resp = @stub.unary_call(req)
- assert_equal(:COMPRESSABLE, resp.payload.type,
- 'large_unary: payload had the wrong type')
- assert_equal(wanted_response_size, resp.payload.body.length,
- 'large_unary: payload had the wrong length')
- assert_equal(nulls(wanted_response_size), resp.payload.body,
- 'large_unary: payload content is invalid')
- resp
- end
-end
-
-# Args is used to hold the command line info.
-Args = Struct.new(:default_service_account, :host, :host_override,
- :oauth_scope, :port, :secure, :test_case,
- :use_test_ca)
-
-# validates the the command line options, returning them as a Hash.
-def parse_args
- args = Args.new
- args.host_override = 'foo.test.google.fr'
- OptionParser.new do |opts|
- opts.on('--oauth_scope scope',
- 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
- opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
- args['host'] = v
- end
- opts.on('--default_service_account email_address',
- 'email address of the default service account') do |v|
- args['default_service_account'] = v
- end
- opts.on('--server_host_override HOST_OVERRIDE',
- 'override host via a HTTP header') do |v|
- args['host_override'] = v
- end
- opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
- # instance_methods(false) gives only the methods defined in that class
- test_cases = NamedTests.instance_methods(false).map(&:to_s)
- test_case_list = test_cases.join(',')
- opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
- " (#{test_case_list})") { |v| args['test_case'] = v }
- opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
- args['secure'] = v
- end
- opts.on('-t', '--use_test_ca',
- 'if secure, use the test certificate?') do |v|
- args['use_test_ca'] = v
- end
- end.parse!
- _check_args(args)
-end
-
-def _check_args(args)
- %w(host port test_case).each do |a|
- if args[a].nil?
- fail(OptionParser::MissingArgument, "please specify --#{arg}")
- end
- end
- args
-end
-
-def main
- opts = parse_args
- stub = create_stub(opts)
- NamedTests.new(stub, opts).method(opts['test_case']).call
-end
+pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-main
+require 'test/client'
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb
index 2ba8d2c19e..c6b0d00ec6 100755
--- a/src/ruby/bin/interop/interop_server.rb
+++ b/src/ruby/bin/interop/interop_server.rb
@@ -29,6 +29,12 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# #######################################################################
+# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb
+#
+# This file remains to support existing tools and scripts that use it.
+# ######################################################################
+#
# interop_server is a Testing app that runs a gRPC interop testing server.
#
# It helps validate interoperation b/w gRPC in different environments
@@ -38,157 +44,7 @@
# Usage: $ path/to/interop_server.rb --port
this_dir = File.expand_path(File.dirname(__FILE__))
-lib_dir = File.join(File.dirname(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 'forwardable'
-require 'optparse'
-
-require 'grpc'
-
-require 'test/cpp/interop/test_services'
-require 'test/cpp/interop/messages'
-require 'test/cpp/interop/empty'
-
-# loads the certificates by the test server.
-def load_test_certs
- this_dir = File.expand_path(File.dirname(__FILE__))
- data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
- files = ['ca.pem', 'server1.key', 'server1.pem']
- files.map { |f| File.open(File.join(data_dir, f)).read }
-end
-
-# creates a ServerCredentials from the test certificates.
-def test_server_creds
- certs = load_test_certs
- GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
-end
-
-# produces a string of null chars (\0) of length l.
-def nulls(l)
- fail 'requires #{l} to be +ve' if l < 0
- [].pack('x' * l).force_encoding('utf-8')
-end
-
-# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
-class EnumeratorQueue
- extend Forwardable
- def_delegators :@q, :push
-
- def initialize(sentinel)
- @q = Queue.new
- @sentinel = sentinel
- end
-
- def each_item
- return enum_for(:each_item) unless block_given?
- loop do
- r = @q.pop
- break if r.equal?(@sentinel)
- fail r if r.is_a? Exception
- yield r
- end
- end
-end
-
-# A runnable implementation of the schema-specified testing service, with each
-# service method implemented as required by the interop testing spec.
-class TestTarget < Grpc::Testing::TestService::Service
- include Grpc::Testing
- include Grpc::Testing::PayloadType
-
- def empty_call(_empty, _call)
- Empty.new
- end
-
- def unary_call(simple_req, _call)
- req_size = simple_req.response_size
- SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
- body: nulls(req_size)))
- end
-
- def streaming_input_call(call)
- sizes = call.each_remote_read.map { |x| x.payload.body.length }
- sum = sizes.inject { |s, x| s + x }
- StreamingInputCallResponse.new(aggregated_payload_size: sum)
- end
-
- def streaming_output_call(req, _call)
- cls = StreamingOutputCallResponse
- req.response_parameters.map do |p|
- cls.new(payload: Payload.new(type: req.response_type,
- body: nulls(p.size)))
- end
- end
-
- def full_duplex_call(reqs)
- # reqs is a lazy Enumerator of the requests sent by the client.
- q = EnumeratorQueue.new(self)
- cls = StreamingOutputCallResponse
- Thread.new do
- begin
- GRPC.logger.info('interop-server: started receiving')
- reqs.each do |req|
- resp_size = req.response_parameters[0].size
- GRPC.logger.info("read a req, response size is #{resp_size}")
- resp = cls.new(payload: Payload.new(type: req.response_type,
- body: nulls(resp_size)))
- q.push(resp)
- end
- GRPC.logger.info('interop-server: finished receiving')
- q.push(self)
- rescue StandardError => e
- GRPC.logger.info('interop-server: failed')
- GRPC.logger.warn(e)
- q.push(e) # share the exception with the enumerator
- end
- end
- q.each_item
- end
-
- def half_duplex_call(reqs)
- # TODO: update with unique behaviour of the half_duplex_call if that's
- # ever required by any of the tests.
- full_duplex_call(reqs)
- end
-end
-
-# validates the the command line options, returning them as a Hash.
-def parse_options
- options = {
- 'port' => nil,
- 'secure' => false
- }
- OptionParser.new do |opts|
- opts.banner = 'Usage: --port port'
- opts.on('--port PORT', 'server port') do |v|
- options['port'] = v
- end
- opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
- options['secure'] = v
- end
- end.parse!
-
- if options['port'].nil?
- fail(OptionParser::MissingArgument, 'please specify --port')
- end
- options
-end
-
-def main
- opts = parse_options
- host = "0.0.0.0:#{opts['port']}"
- s = GRPC::RpcServer.new
- if opts['secure']
- s.add_http2_port(host, test_server_creds)
- GRPC.logger.info("... running securely on #{host}")
- else
- s.add_http2_port(host)
- GRPC.logger.info("... running insecurely on #{host}")
- end
- s.handle(TestTarget)
- s.run_till_terminated
-end
+pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-main
+require 'test/server'
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 88659da535..36c6818a7e 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -170,7 +170,7 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
grpc_call *call = NULL;
grpc_call_error err;
TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
- err = grpc_call_cancel(call);
+ err = grpc_call_cancel(call, NULL);
if (err != GRPC_CALL_OK) {
rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@@ -526,6 +526,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
};
st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
st->ops[st->op_num].flags = 0;
+ st->ops[st->op_num].reserved = NULL;
st->op_num++;
}
}
@@ -615,7 +616,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
/* call grpc_call_start_batch, then wait for it to complete using
* pluck_event */
- err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag));
+ err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag), NULL);
if (err != GRPC_CALL_OK) {
grpc_run_batch_stack_cleanup(&st);
rb_raise(grpc_rb_eCallError,
@@ -629,13 +630,9 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
return Qnil;
}
- if (!ev.success) {
- grpc_run_batch_stack_cleanup(&st);
- rb_raise(grpc_rb_eCallError, "start_batch completion failed");
- return Qnil;
- }
- /* Build and return the BatchResult struct result */
+ /* Build and return the BatchResult struct result,
+ if there is an error, it's reflected in the status */
result = grpc_run_batch_stack_build_result(&st);
grpc_run_batch_stack_cleanup(&st);
return result;
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 2129ba3485..6491aa4fb4 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -147,7 +147,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
target_chars = StringValueCStr(target);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
if (credentials == Qnil) {
- ch = grpc_insecure_channel_create(target_chars, &args);
+ ch = grpc_insecure_channel_create(target_chars, &args, NULL);
} else {
creds = grpc_rb_get_wrapped_credentials(credentials);
ch = grpc_secure_channel_create(creds, target_chars, &args);
@@ -288,7 +288,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars,
host_chars, grpc_rb_time_timeval(
deadline,
- /* absolute time */ 0));
+ /* absolute time */ 0), NULL);
if (call == NULL) {
rb_raise(rb_eRuntimeError, "cannot create call with method %s",
method_chars);
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index b6674d7682..0bc9eb2a97 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -56,7 +56,7 @@ typedef struct next_call_stack {
static void *grpc_rb_completion_queue_next_no_gil(void *param) {
next_call_stack *const next_call = (next_call_stack*)param;
next_call->event =
- grpc_completion_queue_next(next_call->cq, next_call->timeout);
+ grpc_completion_queue_next(next_call->cq, next_call->timeout, NULL);
return NULL;
}
@@ -64,7 +64,7 @@ static void *grpc_rb_completion_queue_next_no_gil(void *param) {
static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
next_call_stack *const next_call = (next_call_stack*)param;
next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag,
- next_call->timeout);
+ next_call->timeout, NULL);
return NULL;
}
@@ -128,7 +128,7 @@ static rb_data_type_t grpc_rb_completion_queue_data_type = {
/* Allocates a completion queue. */
static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
- grpc_completion_queue *cq = grpc_completion_queue_create();
+ grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
if (cq == NULL) {
rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
}
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 79a4ae8757..7e76349d2e 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -128,7 +128,7 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) {
TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type,
wrapper);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
- srv = grpc_server_create(&args);
+ srv = grpc_server_create(&args, NULL);
if (args.args != NULL) {
xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
@@ -136,7 +136,7 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) {
if (srv == NULL) {
rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why");
}
- grpc_server_register_completion_queue(srv, cq);
+ grpc_server_register_completion_queue(srv, cq, NULL);
wrapper->wrapped = srv;
/* Add the cq as the server's mark object. This ensures the ruby cq can't be
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index eb748458b9..20a6206e7e 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -24,16 +24,16 @@ Gem::Specification.new do |s|
%w(math noproto).each do |b|
s.executables += ["#{b}_client.rb", "#{b}_server.rb"]
end
- s.require_paths = %w( bin lib )
+ s.executables += %w(grpc_ruby_interop_client grpc_ruby_interop_server)
+ s.require_paths = %w( bin lib pb )
s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
- s.add_dependency 'googleauth', '~> 0.4' # reqd for interop tests
- s.add_dependency 'logging', '~> 2.0'
- s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests
+ s.add_dependency 'googleauth', '~> 0.4'
- s.add_development_dependency 'simplecov', '~> 0.9'
s.add_development_dependency 'bundler', '~> 1.9'
+ s.add_development_dependency 'logging', '~> 2.0'
+ s.add_development_dependency 'simplecov', '~> 0.9'
s.add_development_dependency 'rake', '~> 10.4'
s.add_development_dependency 'rake-compiler', '~> 0.9'
s.add_development_dependency 'rspec', '~> 3.2'
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 215c0069a3..17da401c6b 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -74,8 +74,7 @@ module GRPC
#
# @param call [Call] a call on which to start and invocation
# @param q [CompletionQueue] the completion queue
- # @param deadline [Fixnum,TimeSpec] the deadline
- def self.client_invoke(call, q, _deadline, **kw)
+ def self.client_invoke(call, q, **kw)
fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
unless q.is_a? Core::CompletionQueue
fail(TypeError, '!Core::CompletionQueue')
@@ -418,7 +417,7 @@ module GRPC
# @return [Enumerator, nil] a response Enumerator
def bidi_streamer(requests, **kw, &blk)
start_call(**kw) unless @started
- bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
+ bd = BidiCall.new(@call, @cq, @marshal, @unmarshal)
bd.run_on_client(requests, @op_notifier, &blk)
end
@@ -434,7 +433,7 @@ module GRPC
#
# @param gen_each_reply [Proc] generates the BiDi stream replies
def run_server_bidi(gen_each_reply)
- bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
+ bd = BidiCall.new(@call, @cq, @marshal, @unmarshal)
bd.run_on_server(gen_each_reply)
end
@@ -456,7 +455,7 @@ module GRPC
# Starts the call if not already started
def start_call(**kw)
return if @started
- @metadata_tag = ActiveCall.client_invoke(@call, @cq, @deadline, **kw)
+ @metadata_tag = ActiveCall.client_invoke(@call, @cq, **kw)
@started = true
end
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 3b0c71395c..9dbbb74caf 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -56,15 +56,13 @@ module GRPC
# the call
# @param marshal [Function] f(obj)->string that marshal requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [Fixnum] the deadline for the call to complete
- def initialize(call, q, marshal, unmarshal, deadline)
+ def initialize(call, q, marshal, unmarshal)
fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
unless q.is_a? Core::CompletionQueue
fail(ArgumentError, 'not a CompletionQueue')
end
@call = call
@cq = q
- @deadline = deadline
@marshal = marshal
@op_notifier = nil # signals completion on clients
@readq = Queue.new
@@ -99,7 +97,7 @@ module GRPC
# @param gen_each_reply [Proc] generates the BiDi stream replies.
def run_on_server(gen_each_reply)
replys = gen_each_reply.call(each_queued_msg)
- @loop_th = start_read_loop
+ @loop_th = start_read_loop(is_client: false)
write_loop(replys, is_client: false)
end
@@ -127,7 +125,7 @@ module GRPC
count += 1
req = @readq.pop
GRPC.logger.debug("each_queued_msg: req = #{req}")
- throw req if req.is_a? StandardError
+ fail req if req.is_a? StandardError
break if req.equal?(END_OF_READS)
yield req
end
@@ -147,12 +145,9 @@ module GRPC
GRPC.logger.debug("bidi-write-loop: #{count} writes done")
if is_client
GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting")
- batch_result = @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
- SEND_CLOSE_FROM_CLIENT => nil,
- RECV_STATUS_ON_CLIENT => nil)
- @call.status = batch_result.status
- batch_result.check_status
- GRPC.logger.debug("bidi-write-loop: done status #{@call.status}")
+ @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+ SEND_CLOSE_FROM_CLIENT => nil)
+ GRPC.logger.debug('bidi-write-loop: done')
notify_done
end
GRPC.logger.debug('bidi-write-loop: finished')
@@ -164,7 +159,7 @@ module GRPC
end
# starts the read loop
- def start_read_loop
+ def start_read_loop(is_client: true)
Thread.new do
GRPC.logger.debug('bidi-read-loop: starting')
begin
@@ -177,9 +172,19 @@ module GRPC
# TODO: ensure metadata is read if available, currently it's not
batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
RECV_MESSAGE => nil)
+
# handle the next message
if batch_result.message.nil?
GRPC.logger.debug("bidi-read-loop: null batch #{batch_result}")
+
+ if is_client
+ batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
+ RECV_STATUS_ON_CLIENT => nil)
+ @call.status = batch_result.status
+ batch_result.check_status
+ GRPC.logger.debug("bidi-read-loop: done status #{@call.status}")
+ end
+
@readq.push(END_OF_READS)
GRPC.logger.debug('bidi-read-loop: done reading!')
break
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index cce718537c..24ec1793f6 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -161,15 +161,21 @@ module GRPC
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
# @param timeout [Numeric] (optional) the max completion time in seconds
+ # @param deadline [Time] (optional) the time the request should complete
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
# @param return_op [true|false] return an Operation if true
# @return [Object] the response received from the server
- def request_response(method, req, marshal, unmarshal, timeout = nil,
+ def request_response(method, req, marshal, unmarshal,
+ deadline: nil,
+ timeout: nil,
return_op: false,
parent: parent,
**kw)
- c = new_active_call(method, marshal, unmarshal, timeout, parent: parent)
+ c = new_active_call(method, marshal, unmarshal,
+ deadline: deadline,
+ timeout: timeout,
+ parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.request_response(req, **md) unless return_op
@@ -222,16 +228,22 @@ module GRPC
# @param requests [Object] an Enumerable of requests to send
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param timeout [Numeric] the max completion time in seconds
+ # @param timeout [Numeric] (optional) the max completion time in seconds
+ # @param deadline [Time] (optional) the time the request should complete
# @param return_op [true|false] return an Operation if true
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
# @return [Object|Operation] the response received from the server
- def client_streamer(method, requests, marshal, unmarshal, timeout = nil,
+ def client_streamer(method, requests, marshal, unmarshal,
+ deadline: nil,
+ timeout: nil,
return_op: false,
parent: nil,
**kw)
- c = new_active_call(method, marshal, unmarshal, timeout, parent: parent)
+ c = new_active_call(method, marshal, unmarshal,
+ deadline: deadline,
+ timeout: timeout,
+ parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.client_streamer(requests, **md) unless return_op
@@ -292,18 +304,24 @@ module GRPC
# @param req [Object] the request sent to the server
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param timeout [Numeric] the max completion time in seconds
+ # @param timeout [Numeric] (optional) the max completion time in seconds
+ # @param deadline [Time] (optional) the time the request should complete
# @param return_op [true|false]return an Operation if true
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
# @param blk [Block] when provided, is executed for each response
# @return [Enumerator|Operation|nil] as discussed above
- def server_streamer(method, req, marshal, unmarshal, timeout = nil,
+ def server_streamer(method, req, marshal, unmarshal,
+ deadline: nil,
+ timeout: nil,
return_op: false,
parent: nil,
**kw,
&blk)
- c = new_active_call(method, marshal, unmarshal, timeout, parent: parent)
+ c = new_active_call(method, marshal, unmarshal,
+ deadline: deadline,
+ timeout: timeout,
+ parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.server_streamer(req, **md, &blk) unless return_op
@@ -404,17 +422,23 @@ module GRPC
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
# @param timeout [Numeric] (optional) the max completion time in seconds
+ # @param deadline [Time] (optional) the time the request should complete
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
# @param return_op [true|false] return an Operation if true
# @param blk [Block] when provided, is executed for each response
# @return [Enumerator|nil|Operation] as discussed above
- def bidi_streamer(method, requests, marshal, unmarshal, timeout = nil,
+ def bidi_streamer(method, requests, marshal, unmarshal,
+ deadline: nil,
+ timeout: nil,
return_op: false,
parent: nil,
**kw,
&blk)
- c = new_active_call(method, marshal, unmarshal, timeout, parent: parent)
+ c = new_active_call(method, marshal, unmarshal,
+ deadline: deadline,
+ timeout: timeout,
+ parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.bidi_streamer(requests, **md, &blk) unless return_op
@@ -438,8 +462,13 @@ module GRPC
# @param parent [Grpc::Call] a parent call, available when calls are
# made from server
# @param timeout [TimeConst]
- def new_active_call(method, marshal, unmarshal, timeout = nil, parent: nil)
- deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
+ def new_active_call(method, marshal, unmarshal,
+ deadline: nil,
+ timeout: nil,
+ parent: nil)
+ if deadline.nil?
+ deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
+ end
call = @ch.create_call(@queue,
parent, # parent call
@propagate_mask, # propagation options
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 3b9743ea66..80ff669cca 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -174,26 +174,24 @@ module GRPC
unmarshal = desc.unmarshal_proc(:output)
route = "/#{route_prefix}/#{name}"
if desc.request_response?
- define_method(mth_name) do |req, deadline = nil, **kw|
+ define_method(mth_name) do |req, **kw|
GRPC.logger.debug("calling #{@host}:#{route}")
- request_response(route, req, marshal, unmarshal, deadline, **kw)
+ request_response(route, req, marshal, unmarshal, **kw)
end
elsif desc.client_streamer?
- define_method(mth_name) do |reqs, deadline = nil, **kw|
+ define_method(mth_name) do |reqs, **kw|
GRPC.logger.debug("calling #{@host}:#{route}")
- client_streamer(route, reqs, marshal, unmarshal, deadline, **kw)
+ client_streamer(route, reqs, marshal, unmarshal, **kw)
end
elsif desc.server_streamer?
- define_method(mth_name) do |req, deadline = nil, **kw, &blk|
+ define_method(mth_name) do |req, **kw, &blk|
GRPC.logger.debug("calling #{@host}:#{route}")
- server_streamer(route, req, marshal, unmarshal, deadline, **kw,
- &blk)
+ server_streamer(route, req, marshal, unmarshal, **kw, &blk)
end
else # is a bidi_stream
- define_method(mth_name) do |reqs, deadline = nil, **kw, &blk|
+ define_method(mth_name) do |reqs, **kw, &blk|
GRPC.logger.debug("calling #{@host}:#{route}")
- bidi_streamer(route, reqs, marshal, unmarshal, deadline, **kw,
- &blk)
+ bidi_streamer(route, reqs, marshal, unmarshal, **kw, &blk)
end
end
end
diff --git a/src/ruby/lib/grpc/logconfig.rb b/src/ruby/lib/grpc/logconfig.rb
index e9b4aa3c95..6b442febcb 100644
--- a/src/ruby/lib/grpc/logconfig.rb
+++ b/src/ruby/lib/grpc/logconfig.rb
@@ -27,17 +27,33 @@
# (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 'logging'
-
# GRPC contains the General RPC module.
module GRPC
- extend Logging.globally
-end
+ # DefaultLogger is a module included in GRPC if no other logging is set up for
+ # it. See ../spec/spec_helpers an example of where other logging is added.
+ module DefaultLogger
+ def logger
+ LOGGER
+ end
+
+ private
+
+ # NoopLogger implements the methods of Ruby's conventional logging interface
+ # that are actually used internally within gRPC with a noop implementation.
+ class NoopLogger
+ def info(_ignored)
+ end
-Logging.logger.root.appenders = Logging.appenders.stdout
-Logging.logger.root.level = :info
+ def debug(_ignored)
+ end
-# TODO: provide command-line configuration for logging
-Logging.logger['GRPC'].level = :info
-Logging.logger['GRPC::ActiveCall'].level = :info
-Logging.logger['GRPC::BidiCall'].level = :info
+ def warn(_ignored)
+ end
+ end
+
+ LOGGER = NoopLogger.new
+ end
+
+ # Inject the noop #logger if no module-level logger method has been injected.
+ extend DefaultLogger unless methods.include?(:logger)
+end
diff --git a/src/ruby/pb/README.md b/src/ruby/pb/README.md
new file mode 100644
index 0000000000..84644e1098
--- /dev/null
+++ b/src/ruby/pb/README.md
@@ -0,0 +1,42 @@
+Protocol Buffers
+================
+
+This folder contains protocol buffers provided with gRPC ruby, and the generated
+code to them.
+
+PREREQUISITES
+-------------
+
+The code is is generated using the protoc (> 3.0.0.alpha.1) and the
+grpc_ruby_plugin. These must be installed to regenerate the IDL defined
+classes, but that's not necessary just to use them.
+
+health_check/v1alpha
+--------------------
+
+This package defines the surface of a simple health check service that gRPC
+servers may choose to implement, and provides an implementation for it. To
+re-generate the surface.
+
+```bash
+$ # (from this directory)
+$ protoc -I . grpc/health/v1alpha/health.proto \
+ --grpc_out=. \
+ --ruby_out=. \
+ --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
+```
+
+test
+----
+
+This package defines the surface of the gRPC interop test service and client
+To re-generate the surface, it's necessary to have checked-out versions of
+the grpc interop test proto, e.g, by having the full gRPC repository. E.g,
+
+```bash
+$ # (from this directory within the grpc repo)
+$ protoc -I../../.. ../../../test/proto/{messages,test,empty}.proto \
+ --grpc_out=. \
+ --ruby_out=. \
+ --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
+```
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
new file mode 100644
index 0000000000..8c692e74f9
--- /dev/null
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -0,0 +1,75 @@
+# 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.
+
+require 'grpc'
+require 'grpc/health/v1alpha/health_services'
+require 'thread'
+
+module Grpc
+ # Health contains classes and modules that support providing a health check
+ # service.
+ module Health
+ # Checker is implementation of the schema-specified health checking service.
+ class Checker < V1alpha::Health::Service
+ StatusCodes = GRPC::Core::StatusCodes
+ HealthCheckResponse = V1alpha::HealthCheckResponse
+
+ # Initializes the statuses of participating services
+ def initialize
+ @statuses = {}
+ @status_mutex = Mutex.new # guards access to @statuses
+ end
+
+ # Implements the rpc IDL API method
+ def check(req, _call)
+ status = nil
+ @status_mutex.synchronize do
+ status = @statuses["#{req.host}/#{req.service}"]
+ end
+ fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil?
+ HealthCheckResponse.new(status: status)
+ end
+
+ # Adds the health status for a given host and service.
+ def add_status(host, service, status)
+ @status_mutex.synchronize { @statuses["#{host}/#{service}"] = status }
+ end
+
+ # Clears the status for the given host or service.
+ def clear_status(host, service)
+ @status_mutex.synchronize { @statuses.delete("#{host}/#{service}") }
+ end
+
+ # Clears alls the statuses.
+ def clear_all
+ @status_mutex.synchronize { @statuses = {} }
+ end
+ end
+ end
+end
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.proto b/src/ruby/pb/grpc/health/v1alpha/health.proto
new file mode 100644
index 0000000000..d31df1e0a7
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health.proto
@@ -0,0 +1,50 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package grpc.health.v1alpha;
+
+message HealthCheckRequest {
+ string host = 1;
+ string service = 2;
+}
+
+message HealthCheckResponse {
+ enum ServingStatus {
+ UNKNOWN = 0;
+ SERVING = 1;
+ NOT_SERVING = 2;
+ }
+ ServingStatus status = 1;
+}
+
+service Health {
+ rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+} \ No newline at end of file
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.rb b/src/ruby/pb/grpc/health/v1alpha/health.rb
new file mode 100644
index 0000000000..9c04298ea5
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health.rb
@@ -0,0 +1,29 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: grpc/health/v1alpha/health.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.health.v1alpha.HealthCheckRequest" do
+ optional :host, :string, 1
+ optional :service, :string, 2
+ end
+ add_message "grpc.health.v1alpha.HealthCheckResponse" do
+ optional :status, :enum, 1, "grpc.health.v1alpha.HealthCheckResponse.ServingStatus"
+ end
+ add_enum "grpc.health.v1alpha.HealthCheckResponse.ServingStatus" do
+ value :UNKNOWN, 0
+ value :SERVING, 1
+ value :NOT_SERVING, 2
+ end
+end
+
+module Grpc
+ module Health
+ module V1alpha
+ HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckRequest").msgclass
+ HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse").msgclass
+ HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse.ServingStatus").enummodule
+ end
+ end
+end
diff --git a/src/ruby/pb/grpc/health/v1alpha/health_services.rb b/src/ruby/pb/grpc/health/v1alpha/health_services.rb
new file mode 100644
index 0000000000..d5cba2e9ec
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health_services.rb
@@ -0,0 +1,28 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: grpc/health/v1alpha/health.proto for package 'grpc.health.v1alpha'
+
+require 'grpc'
+require 'grpc/health/v1alpha/health'
+
+module Grpc
+ module Health
+ module V1alpha
+ module Health
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.health.v1alpha.Health'
+
+ rpc :Check, HealthCheckRequest, HealthCheckResponse
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+ end
+end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
new file mode 100755
index 0000000000..164e304b4d
--- /dev/null
+++ b/src/ruby/pb/test/client.rb
@@ -0,0 +1,453 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+# client is a testing tool that accesses a gRPC interop testing server and runs
+# a test on it.
+#
+# Helps validate interoperation b/w different gRPC implementations.
+#
+# Usage: $ path/to/client.rb --server_host=<hostname> \
+# --server_port=<port> \
+# --test_case=<testcase_name>
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
+pb_dir = File.dirname(File.dirname(this_dir))
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'optparse'
+
+require 'grpc'
+require 'googleauth'
+require 'google/protobuf'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+require 'test/proto/test_services'
+
+require 'signet/ssl_config'
+
+AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
+
+# AssertionError is use to indicate interop test failures.
+class AssertionError < RuntimeError; end
+
+# Fails with AssertionError if the block does evaluate to true
+def assert(msg = 'unknown cause')
+ fail 'No assertion block provided' unless block_given?
+ fail AssertionError, msg unless yield
+end
+
+# loads the certificates used to access the test server securely.
+def load_test_certs
+ this_dir = File.expand_path(File.dirname(__FILE__))
+ data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
+ files = ['ca.pem', 'server1.key', 'server1.pem']
+ files.map { |f| File.open(File.join(data_dir, f)).read }
+end
+
+# loads the certificates used to access the test server securely.
+def load_prod_cert
+ fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
+ GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
+ File.open(ENV['SSL_CERT_FILE']).read
+end
+
+# creates SSL Credentials from the test certificates.
+def test_creds
+ certs = load_test_certs
+ GRPC::Core::Credentials.new(certs[0])
+end
+
+# creates SSL Credentials from the production certificates.
+def prod_creds
+ cert_text = load_prod_cert
+ GRPC::Core::Credentials.new(cert_text)
+end
+
+# creates the SSL Credentials.
+def ssl_creds(use_test_ca)
+ return test_creds if use_test_ca
+ prod_creds
+end
+
+# creates a test stub that accesses host:port securely.
+def create_stub(opts)
+ address = "#{opts.host}:#{opts.port}"
+ if opts.secure
+ stub_opts = {
+ :creds => ssl_creds(opts.use_test_ca),
+ GRPC::Core::Channel::SSL_TARGET => opts.host_override
+ }
+
+ # Add service account creds if specified
+ wants_creds = %w(all compute_engine_creds service_account_creds)
+ if wants_creds.include?(opts.test_case)
+ unless opts.oauth_scope.nil?
+ auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
+ stub_opts[:update_metadata] = auth_creds.updater_proc
+ end
+ end
+
+ if opts.test_case == 'oauth2_auth_token'
+ auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
+ kw = auth_creds.updater_proc.call({}) # gives as an auth token
+
+ # use a metadata update proc that just adds the auth token.
+ stub_opts[:update_metadata] = proc { |md| md.merge(kw) }
+ end
+
+ if opts.test_case == 'jwt_token_creds' # don't use a scope
+ auth_creds = Google::Auth.get_application_default
+ stub_opts[:update_metadata] = auth_creds.updater_proc
+ end
+
+ GRPC.logger.info("... connecting securely to #{address}")
+ Grpc::Testing::TestService::Stub.new(address, **stub_opts)
+ else
+ GRPC.logger.info("... connecting insecurely to #{address}")
+ Grpc::Testing::TestService::Stub.new(address)
+ end
+end
+
+# produces a string of null chars (\0) of length l.
+def nulls(l)
+ fail 'requires #{l} to be +ve' if l < 0
+ [].pack('x' * l).force_encoding('utf-8')
+end
+
+# a PingPongPlayer implements the ping pong bidi test.
+class PingPongPlayer
+ include Grpc::Testing
+ include Grpc::Testing::PayloadType
+ attr_accessor :queue
+ attr_accessor :canceller_op
+
+ # reqs is the enumerator over the requests
+ def initialize(msg_sizes)
+ @queue = Queue.new
+ @msg_sizes = msg_sizes
+ @canceller_op = nil # used to cancel after the first response
+ end
+
+ def each_item
+ return enum_for(:each_item) unless block_given?
+ req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short
+ count = 0
+ @msg_sizes.each do |m|
+ req_size, resp_size = m
+ req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
+ response_type: :COMPRESSABLE,
+ response_parameters: [p_cls.new(size: resp_size)])
+ yield req
+ resp = @queue.pop
+ assert('payload type is wrong') { :COMPRESSABLE == resp.payload.type }
+ assert("payload body #{count} has the wrong length") do
+ resp_size == resp.payload.body.length
+ end
+ p "OK: ping_pong #{count}"
+ count += 1
+ unless @canceller_op.nil?
+ canceller_op.cancel
+ break
+ end
+ end
+ end
+end
+
+# defines methods corresponding to each interop test case.
+class NamedTests
+ include Grpc::Testing
+ include Grpc::Testing::PayloadType
+
+ def initialize(stub, args)
+ @stub = stub
+ @args = args
+ end
+
+ def empty_unary
+ resp = @stub.empty_call(Empty.new)
+ assert('empty_unary: invalid response') { resp.is_a?(Empty) }
+ p 'OK: empty_unary'
+ end
+
+ def large_unary
+ perform_large_unary
+ p 'OK: large_unary'
+ end
+
+ def service_account_creds
+ # ignore this test if the oauth options are not set
+ if @args.oauth_scope.nil?
+ p 'NOT RUN: service_account_creds; no service_account settings'
+ return
+ end
+ json_key = File.read(ENV[AUTH_ENV])
+ wanted_email = MultiJson.load(json_key)['client_email']
+ resp = perform_large_unary(fill_username: true,
+ fill_oauth_scope: true)
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
+ assert("#{__callee__}: bad oauth scope") do
+ @args.oauth_scope.include?(resp.oauth_scope)
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def jwt_token_creds
+ json_key = File.read(ENV[AUTH_ENV])
+ wanted_email = MultiJson.load(json_key)['client_email']
+ resp = perform_large_unary(fill_username: true)
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
+ p "OK: #{__callee__}"
+ end
+
+ def compute_engine_creds
+ resp = perform_large_unary(fill_username: true,
+ fill_oauth_scope: true)
+ assert("#{__callee__}: bad username") do
+ @args.default_service_account == resp.username
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def oauth2_auth_token
+ resp = perform_large_unary(fill_username: true,
+ fill_oauth_scope: true)
+ json_key = File.read(ENV[AUTH_ENV])
+ wanted_email = MultiJson.load(json_key)['client_email']
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
+ assert("#{__callee__}: bad oauth scope") do
+ @args.oauth_scope.include?(resp.oauth_scope)
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def per_rpc_creds
+ auth_creds = Google::Auth.get_application_default(@args.oauth_scope)
+ kw = auth_creds.updater_proc.call({})
+ resp = perform_large_unary(fill_username: true,
+ fill_oauth_scope: true,
+ **kw)
+ json_key = File.read(ENV[AUTH_ENV])
+ wanted_email = MultiJson.load(json_key)['client_email']
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
+ assert("#{__callee__}: bad oauth scope") do
+ @args.oauth_scope.include?(resp.oauth_scope)
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def client_streaming
+ msg_sizes = [27_182, 8, 1828, 45_904]
+ wanted_aggregate_size = 74_922
+ reqs = msg_sizes.map do |x|
+ req = Payload.new(body: nulls(x))
+ StreamingInputCallRequest.new(payload: req)
+ end
+ resp = @stub.streaming_input_call(reqs)
+ assert("#{__callee__}: aggregate payload size is incorrect") do
+ wanted_aggregate_size == resp.aggregated_payload_size
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def server_streaming
+ msg_sizes = [31_415, 9, 2653, 58_979]
+ response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
+ req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
+ response_parameters: response_spec)
+ resps = @stub.streaming_output_call(req)
+ resps.each_with_index do |r, i|
+ assert("#{__callee__}: too many responses") { i < msg_sizes.length }
+ assert("#{__callee__}: payload body #{i} has the wrong length") do
+ msg_sizes[i] == r.payload.body.length
+ end
+ assert("#{__callee__}: payload type is wrong") do
+ :COMPRESSABLE == r.payload.type
+ end
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def ping_pong
+ msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
+ ppp = PingPongPlayer.new(msg_sizes)
+ resps = @stub.full_duplex_call(ppp.each_item)
+ resps.each { |r| ppp.queue.push(r) }
+ p "OK: #{__callee__}"
+ end
+
+ def timeout_on_sleeping_server
+ msg_sizes = [[27_182, 31_415]]
+ ppp = PingPongPlayer.new(msg_sizes)
+ resps = @stub.full_duplex_call(ppp.each_item, timeout: 0.001)
+ resps.each { |r| ppp.queue.push(r) }
+ fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)'
+ rescue GRPC::BadStatus => e
+ assert("#{__callee__}: status was wrong") do
+ e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def empty_stream
+ ppp = PingPongPlayer.new([])
+ resps = @stub.full_duplex_call(ppp.each_item)
+ count = 0
+ resps.each do |r|
+ ppp.queue.push(r)
+ count += 1
+ end
+ assert("#{__callee__}: too many responses expected 0") do
+ count == 0
+ end
+ p "OK: #{__callee__}"
+ end
+
+ def cancel_after_begin
+ msg_sizes = [27_182, 8, 1828, 45_904]
+ reqs = msg_sizes.map do |x|
+ req = Payload.new(body: nulls(x))
+ StreamingInputCallRequest.new(payload: req)
+ end
+ op = @stub.streaming_input_call(reqs, return_op: true)
+ op.cancel
+ op.execute
+ fail 'Should have raised GRPC:Cancelled'
+ rescue GRPC::Cancelled
+ assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
+ p "OK: #{__callee__}"
+ end
+
+ def cancel_after_first_response
+ msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
+ ppp = PingPongPlayer.new(msg_sizes)
+ op = @stub.full_duplex_call(ppp.each_item, return_op: true)
+ ppp.canceller_op = op # causes ppp to cancel after the 1st message
+ op.execute.each { |r| ppp.queue.push(r) }
+ fail 'Should have raised GRPC:Cancelled'
+ rescue GRPC::Cancelled
+ assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
+ op.wait
+ p "OK: #{__callee__}"
+ end
+
+ def all
+ all_methods = NamedTests.instance_methods(false).map(&:to_s)
+ all_methods.each do |m|
+ next if m == 'all' || m.start_with?('assert')
+ p "TESTCASE: #{m}"
+ method(m).call
+ end
+ end
+
+ private
+
+ def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw)
+ req_size, wanted_response_size = 271_828, 314_159
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
+ response_size: wanted_response_size,
+ payload: payload)
+ req.fill_username = fill_username
+ req.fill_oauth_scope = fill_oauth_scope
+ resp = @stub.unary_call(req, **kw)
+ assert('payload type is wrong') do
+ :COMPRESSABLE == resp.payload.type
+ end
+ assert('payload body has the wrong length') do
+ wanted_response_size == resp.payload.body.length
+ end
+ assert('payload body is invalid') do
+ nulls(wanted_response_size) == resp.payload.body
+ end
+ resp
+ end
+end
+
+# Args is used to hold the command line info.
+Args = Struct.new(:default_service_account, :host, :host_override,
+ :oauth_scope, :port, :secure, :test_case,
+ :use_test_ca)
+
+# validates the the command line options, returning them as a Hash.
+def parse_args
+ args = Args.new
+ args.host_override = 'foo.test.google.fr'
+ OptionParser.new do |opts|
+ opts.on('--oauth_scope scope',
+ 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
+ opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
+ args['host'] = v
+ end
+ opts.on('--default_service_account email_address',
+ 'email address of the default service account') do |v|
+ args['default_service_account'] = v
+ end
+ opts.on('--server_host_override HOST_OVERRIDE',
+ 'override host via a HTTP header') do |v|
+ args['host_override'] = v
+ end
+ opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
+ # instance_methods(false) gives only the methods defined in that class
+ test_cases = NamedTests.instance_methods(false).map(&:to_s)
+ test_case_list = test_cases.join(',')
+ opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
+ " (#{test_case_list})") { |v| args['test_case'] = v }
+ opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
+ args['secure'] = v
+ end
+ opts.on('-t', '--use_test_ca',
+ 'if secure, use the test certificate?') do |v|
+ args['use_test_ca'] = v
+ end
+ end.parse!
+ _check_args(args)
+end
+
+def _check_args(args)
+ %w(host port test_case).each do |a|
+ if args[a].nil?
+ fail(OptionParser::MissingArgument, "please specify --#{a}")
+ end
+ end
+ args
+end
+
+def main
+ opts = parse_args
+ stub = create_stub(opts)
+ NamedTests.new(stub, opts).method(opts['test_case']).call
+end
+
+main
diff --git a/src/ruby/pb/test/proto/empty.rb b/src/ruby/pb/test/proto/empty.rb
new file mode 100644
index 0000000000..559adcc85e
--- /dev/null
+++ b/src/ruby/pb/test/proto/empty.rb
@@ -0,0 +1,15 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/proto/empty.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.Empty" do
+ end
+end
+
+module Grpc
+ module Testing
+ Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
+ end
+end
diff --git a/src/ruby/bin/interop/test/cpp/interop/messages.rb b/src/ruby/pb/test/proto/messages.rb
index 89c349b406..9b7f977285 100644
--- a/src/ruby/bin/interop/test/cpp/interop/messages.rb
+++ b/src/ruby/pb/test/proto/messages.rb
@@ -1,34 +1,5 @@
-# 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.
-
# Generated by the protocol buffer compiler. DO NOT EDIT!
-# source: test/cpp/interop/messages.proto
+# source: test/proto/messages.proto
require 'google/protobuf'
@@ -37,12 +8,18 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
optional :type, :enum, 1, "grpc.testing.PayloadType"
optional :body, :string, 2
end
+ add_message "grpc.testing.EchoStatus" do
+ optional :code, :int32, 1
+ optional :message, :string, 2
+ end
add_message "grpc.testing.SimpleRequest" do
optional :response_type, :enum, 1, "grpc.testing.PayloadType"
optional :response_size, :int32, 2
optional :payload, :message, 3, "grpc.testing.Payload"
optional :fill_username, :bool, 4
optional :fill_oauth_scope, :bool, 5
+ optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+ optional :response_status, :message, 7, "grpc.testing.EchoStatus"
end
add_message "grpc.testing.SimpleResponse" do
optional :payload, :message, 1, "grpc.testing.Payload"
@@ -63,20 +40,32 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
optional :response_type, :enum, 1, "grpc.testing.PayloadType"
repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
optional :payload, :message, 3, "grpc.testing.Payload"
+ optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+ optional :response_status, :message, 7, "grpc.testing.EchoStatus"
end
add_message "grpc.testing.StreamingOutputCallResponse" do
optional :payload, :message, 1, "grpc.testing.Payload"
end
+ add_message "grpc.testing.ReconnectInfo" do
+ optional :passed, :bool, 1
+ repeated :backoff_ms, :int32, 2
+ end
add_enum "grpc.testing.PayloadType" do
value :COMPRESSABLE, 0
value :UNCOMPRESSABLE, 1
value :RANDOM, 2
end
+ add_enum "grpc.testing.CompressionType" do
+ value :NONE, 0
+ value :GZIP, 1
+ value :DEFLATE, 2
+ end
end
module Grpc
module Testing
Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
+ EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass
StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass
@@ -84,6 +73,8 @@ module Grpc
ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass
StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass
StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
+ ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
+ CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
end
end
diff --git a/src/ruby/pb/test/proto/test.rb b/src/ruby/pb/test/proto/test.rb
new file mode 100644
index 0000000000..100eb6505c
--- /dev/null
+++ b/src/ruby/pb/test/proto/test.rb
@@ -0,0 +1,14 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/proto/test.proto
+
+require 'google/protobuf'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+Google::Protobuf::DescriptorPool.generated_pool.build do
+end
+
+module Grpc
+ module Testing
+ end
+end
diff --git a/src/ruby/pb/test/proto/test_services.rb b/src/ruby/pb/test/proto/test_services.rb
new file mode 100644
index 0000000000..9df9cc5860
--- /dev/null
+++ b/src/ruby/pb/test/proto/test_services.rb
@@ -0,0 +1,64 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: test/proto/test.proto for package 'grpc.testing'
+
+require 'grpc'
+require 'test/proto/test'
+
+module Grpc
+ module Testing
+ module TestService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.TestService'
+
+ rpc :EmptyCall, Empty, Empty
+ rpc :UnaryCall, SimpleRequest, SimpleResponse
+ rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
+ rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
+ rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+ rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ module UnimplementedService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.UnimplementedService'
+
+ rpc :UnimplementedCall, Empty, Empty
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ module ReconnectService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.ReconnectService'
+
+ rpc :Start, Empty, Empty
+ rpc :Stop, Empty, ReconnectInfo
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
new file mode 100755
index 0000000000..e2e1ecbd62
--- /dev/null
+++ b/src/ruby/pb/test/server.rb
@@ -0,0 +1,196 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+# interop_server is a Testing app that runs a gRPC interop testing server.
+#
+# It helps validate interoperation b/w gRPC in different environments
+#
+# Helps validate interoperation b/w different gRPC implementations.
+#
+# Usage: $ path/to/interop_server.rb --port
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
+pb_dir = File.dirname(File.dirname(this_dir))
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'forwardable'
+require 'optparse'
+
+require 'grpc'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+require 'test/proto/test_services'
+
+# loads the certificates by the test server.
+def load_test_certs
+ this_dir = File.expand_path(File.dirname(__FILE__))
+ data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
+ files = ['ca.pem', 'server1.key', 'server1.pem']
+ files.map { |f| File.open(File.join(data_dir, f)).read }
+end
+
+# creates a ServerCredentials from the test certificates.
+def test_server_creds
+ certs = load_test_certs
+ GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+end
+
+# produces a string of null chars (\0) of length l.
+def nulls(l)
+ fail 'requires #{l} to be +ve' if l < 0
+ [].pack('x' * l).force_encoding('utf-8')
+end
+
+# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
+class EnumeratorQueue
+ extend Forwardable
+ def_delegators :@q, :push
+
+ def initialize(sentinel)
+ @q = Queue.new
+ @sentinel = sentinel
+ end
+
+ def each_item
+ return enum_for(:each_item) unless block_given?
+ loop do
+ r = @q.pop
+ break if r.equal?(@sentinel)
+ fail r if r.is_a? Exception
+ yield r
+ end
+ end
+end
+
+# A runnable implementation of the schema-specified testing service, with each
+# service method implemented as required by the interop testing spec.
+class TestTarget < Grpc::Testing::TestService::Service
+ include Grpc::Testing
+ include Grpc::Testing::PayloadType
+
+ def empty_call(_empty, _call)
+ Empty.new
+ end
+
+ def unary_call(simple_req, _call)
+ req_size = simple_req.response_size
+ SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
+ body: nulls(req_size)))
+ end
+
+ def streaming_input_call(call)
+ sizes = call.each_remote_read.map { |x| x.payload.body.length }
+ sum = sizes.inject { |s, x| s + x }
+ StreamingInputCallResponse.new(aggregated_payload_size: sum)
+ end
+
+ def streaming_output_call(req, _call)
+ cls = StreamingOutputCallResponse
+ req.response_parameters.map do |p|
+ cls.new(payload: Payload.new(type: req.response_type,
+ body: nulls(p.size)))
+ end
+ end
+
+ def full_duplex_call(reqs)
+ # reqs is a lazy Enumerator of the requests sent by the client.
+ q = EnumeratorQueue.new(self)
+ cls = StreamingOutputCallResponse
+ Thread.new do
+ begin
+ GRPC.logger.info('interop-server: started receiving')
+ reqs.each do |req|
+ resp_size = req.response_parameters[0].size
+ GRPC.logger.info("read a req, response size is #{resp_size}")
+ resp = cls.new(payload: Payload.new(type: req.response_type,
+ body: nulls(resp_size)))
+ q.push(resp)
+ end
+ GRPC.logger.info('interop-server: finished receiving')
+ q.push(self)
+ rescue StandardError => e
+ GRPC.logger.info('interop-server: failed')
+ GRPC.logger.warn(e)
+ q.push(e) # share the exception with the enumerator
+ end
+ end
+ q.each_item
+ end
+
+ def half_duplex_call(reqs)
+ # TODO: update with unique behaviour of the half_duplex_call if that's
+ # ever required by any of the tests.
+ full_duplex_call(reqs)
+ end
+end
+
+# validates the the command line options, returning them as a Hash.
+def parse_options
+ options = {
+ 'port' => nil,
+ 'secure' => false
+ }
+ OptionParser.new do |opts|
+ opts.banner = 'Usage: --port port'
+ opts.on('--port PORT', 'server port') do |v|
+ options['port'] = v
+ end
+ opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
+ options['secure'] = v
+ end
+ end.parse!
+
+ if options['port'].nil?
+ fail(OptionParser::MissingArgument, 'please specify --port')
+ end
+ options
+end
+
+def main
+ opts = parse_options
+ host = "0.0.0.0:#{opts['port']}"
+ s = GRPC::RpcServer.new
+ if opts['secure']
+ s.add_http2_port(host, test_server_creds)
+ GRPC.logger.info("... running securely on #{host}")
+ else
+ s.add_http2_port(host)
+ GRPC.logger.info("... running insecurely on #{host}")
+ end
+ s.handle(TestTarget)
+ s.run_till_terminated
+end
+
+main
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 0bf65ba2e9..26208b714a 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -57,7 +57,7 @@ describe GRPC::ActiveCall do
describe 'restricted view methods' do
before(:each) do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
@client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -87,7 +87,7 @@ describe GRPC::ActiveCall do
describe '#remote_send' do
it 'allows a client to send a payload to the server' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
@client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -111,7 +111,7 @@ describe GRPC::ActiveCall do
it 'marshals the payload using the marshal func' do
call = make_test_call
- ActiveCall.client_invoke(call, @client_queue, deadline)
+ ActiveCall.client_invoke(call, @client_queue)
marshal = proc { |x| 'marshalled:' + x }
client_call = ActiveCall.new(call, @client_queue, marshal,
@pass_through, deadline)
@@ -134,8 +134,7 @@ describe GRPC::ActiveCall do
describe '#client_invoke' do
it 'sends keywords as metadata to the server when the are present' do
call = make_test_call
- ActiveCall.client_invoke(call, @client_queue, deadline,
- k1: 'v1', k2: 'v2')
+ ActiveCall.client_invoke(call, @client_queue, k1: 'v1', k2: 'v2')
recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
recvd_call = recvd_rpc.call
expect(recvd_call).to_not be_nil
@@ -148,7 +147,7 @@ describe GRPC::ActiveCall do
describe '#remote_read' do
it 'reads the response sent by a server' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -161,7 +160,7 @@ describe GRPC::ActiveCall do
it 'saves no metadata when the server adds no metadata' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -176,7 +175,7 @@ describe GRPC::ActiveCall do
it 'saves metadata add by the server' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -192,7 +191,7 @@ describe GRPC::ActiveCall do
it 'get a nil msg before a status when an OK status is sent' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -209,7 +208,7 @@ describe GRPC::ActiveCall do
it 'unmarshals the response using the unmarshal func' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
unmarshal = proc { |x| 'unmarshalled:' + x }
client_call = ActiveCall.new(call, @client_queue, @pass_through,
unmarshal, deadline,
@@ -234,7 +233,7 @@ describe GRPC::ActiveCall do
it 'the returns an enumerator that can read n responses' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -252,7 +251,7 @@ describe GRPC::ActiveCall do
it 'the returns an enumerator that stops after an OK Status' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -275,7 +274,7 @@ describe GRPC::ActiveCall do
describe '#writes_done' do
it 'finishes ok if the server sends a status response' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -291,7 +290,7 @@ describe GRPC::ActiveCall do
it 'finishes ok if the server sends an early status response' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
@@ -307,7 +306,7 @@ describe GRPC::ActiveCall do
it 'finishes ok if writes_done is true' do
call = make_test_call
- md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
metadata_tag: md_tag)
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 68d4b11790..edcc962a7d 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -408,6 +408,26 @@ describe 'ClientStub' do
it_behaves_like 'bidi streaming'
end
+
+ describe 'without enough time to run' do
+ before(:each) do
+ @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
+ @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
+ server_port = create_test_server
+ @host = "localhost:#{server_port}"
+ end
+
+ it 'should fail with DeadlineExceeded', bidi: true do
+ @server.start
+ stub = GRPC::ClientStub.new(@host, @cq)
+ blk = proc do
+ e = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
+ timeout: 0.001)
+ e.collect { |r| r }
+ end
+ expect(&blk).to raise_error GRPC::BadStatus, /Deadline Exceeded/
+ end
+ end
end
def run_server_streamer(expected_input, replys, status, **kw)
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 0326f6e894..1295fd7fdd 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -396,8 +396,9 @@ describe GRPC::RpcServer do
@srv.wait_till_running
req = EchoMsg.new
stub = SlowStub.new(@host, **client_opts)
- deadline = service.delay + 1.0 # wait for long enough
- expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+ timeout = service.delay + 1.0 # wait for long enough
+ resp = stub.an_rpc(req, timeout: timeout, k1: 'v1', k2: 'v2')
+ expect(resp).to be_a(EchoMsg)
wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
check_md(wanted_md, service.received_md)
@srv.stop
@@ -411,8 +412,8 @@ describe GRPC::RpcServer do
@srv.wait_till_running
req = EchoMsg.new
stub = SlowStub.new(@host, **client_opts)
- deadline = 0.1 # too short for SlowService to respond
- blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
+ timeout = 0.1 # too short for SlowService to respond
+ blk = proc { stub.an_rpc(req, timeout: timeout, k1: 'v1', k2: 'v2') }
expect(&blk).to raise_error GRPC::BadStatus
wanted_md = []
expect(service.received_md).to eq(wanted_md)
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
new file mode 100644
index 0000000000..6999a69105
--- /dev/null
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -0,0 +1,233 @@
+# 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.
+
+require 'grpc'
+require 'grpc/health/v1alpha/health'
+require 'grpc/health/checker'
+require 'open3'
+
+def can_run_codegen_check
+ system('which grpc_ruby_plugin') && system('which protoc')
+end
+
+describe 'Health protobuf code generation' do
+ context 'the health service file used by grpc/health/checker' do
+ if !can_run_codegen_check
+ skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen'
+ else
+ it 'should already be loaded indirectly i.e, used by the other specs' do
+ expect(require('grpc/health/v1alpha/health_services')).to be(false)
+ end
+
+ it 'should have the same content as created by code generation' do
+ root_dir = File.dirname(
+ File.dirname(File.dirname(File.dirname(__FILE__))))
+ pb_dir = File.join(root_dir, 'pb')
+
+ # Get the current content
+ service_path = File.join(pb_dir, 'grpc', 'health', 'v1alpha',
+ 'health_services.rb')
+ want = nil
+ File.open(service_path) { |f| want = f.read }
+
+ # Regenerate it
+ plugin, = Open3.capture2('which', 'grpc_ruby_plugin')
+ plugin = plugin.strip
+ got = nil
+ Dir.mktmpdir do |tmp_dir|
+ gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1alpha',
+ 'health_services.rb')
+ pid = spawn(
+ 'protoc',
+ '-I.',
+ 'grpc/health/v1alpha/health.proto',
+ "--grpc_out=#{tmp_dir}",
+ "--plugin=protoc-gen-grpc=#{plugin}",
+ chdir: pb_dir)
+ Process.wait(pid)
+ File.open(gen_out) { |f| got = f.read }
+ end
+ expect(got).to eq(want)
+ end
+ end
+ end
+end
+
+describe Grpc::Health::Checker do
+ StatusCodes = GRPC::Core::StatusCodes
+ ServingStatus = Grpc::Health::V1alpha::HealthCheckResponse::ServingStatus
+ HCResp = Grpc::Health::V1alpha::HealthCheckResponse
+ HCReq = Grpc::Health::V1alpha::HealthCheckRequest
+ success_tests =
+ [
+ {
+ desc: 'neither host or service are specified',
+ host: '',
+ service: ''
+ }, {
+ desc: 'only the host is specified',
+ host: 'test-fake-host',
+ service: ''
+ }, {
+ desc: 'the host and service are specified',
+ host: 'test-fake-host',
+ service: 'fake-service-1'
+ }, {
+ desc: 'only the service is specified',
+ host: '',
+ service: 'fake-service-2'
+ }
+ ]
+
+ context 'initialization' do
+ it 'can be constructed with no args' do
+ expect(subject).to_not be(nil)
+ end
+ end
+
+ context 'method `add_status` and `check`' do
+ success_tests.each do |t|
+ it "should succeed when #{t[:desc]}" do
+ subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+ got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+ nil)
+ want = HCResp.new(status: ServingStatus::NOT_SERVING)
+ expect(got).to eq(want)
+ end
+ end
+ end
+
+ context 'method `check`' do
+ success_tests.each do |t|
+ it "should fail with NOT_FOUND when #{t[:desc]}" do
+ blk = proc do
+ subject.check(HCReq.new(host: t[:host], service: t[:service]), nil)
+ end
+ expected_msg = /#{StatusCodes::NOT_FOUND}/
+ expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+ end
+ end
+ end
+
+ context 'method `clear_status`' do
+ success_tests.each do |t|
+ it "should fail after clearing status when #{t[:desc]}" do
+ subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+ got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+ nil)
+ want = HCResp.new(status: ServingStatus::NOT_SERVING)
+ expect(got).to eq(want)
+
+ subject.clear_status(t[:host], t[:service])
+ blk = proc do
+ subject.check(HCReq.new(host: t[:host], service: t[:service]),
+ nil)
+ end
+ expected_msg = /#{StatusCodes::NOT_FOUND}/
+ expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+ end
+ end
+ end
+
+ context 'method `clear_all`' do
+ it 'should return NOT_FOUND after being invoked' do
+ success_tests.each do |t|
+ subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+ got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+ nil)
+ want = HCResp.new(status: ServingStatus::NOT_SERVING)
+ expect(got).to eq(want)
+ end
+
+ subject.clear_all
+
+ success_tests.each do |t|
+ blk = proc do
+ subject.check(HCReq.new(host: t[:host], service: t[:service]), nil)
+ end
+ expected_msg = /#{StatusCodes::NOT_FOUND}/
+ expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+ end
+ end
+ end
+
+ describe 'running on RpcServer' do
+ RpcServer = GRPC::RpcServer
+ StatusCodes = GRPC::Core::StatusCodes
+ CheckerStub = Grpc::Health::Checker.rpc_stub_class
+
+ before(:each) do
+ @server_queue = GRPC::Core::CompletionQueue.new
+ server_host = '0.0.0.0:0'
+ @server = GRPC::Core::Server.new(@server_queue, nil)
+ server_port = @server.add_http2_port(server_host)
+ @host = "localhost:#{server_port}"
+ @ch = GRPC::Core::Channel.new(@host, nil)
+ @client_opts = { channel_override: @ch }
+ server_opts = {
+ server_override: @server,
+ completion_queue_override: @server_queue,
+ poll_period: 1
+ }
+ @srv = RpcServer.new(**server_opts)
+ end
+
+ after(:each) do
+ @srv.stop
+ end
+
+ it 'should receive the correct status', server: true do
+ @srv.handle(subject)
+ subject.add_status('', '', ServingStatus::NOT_SERVING)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+
+ stub = CheckerStub.new(@host, **@client_opts)
+ got = stub.check(HCReq.new)
+ want = HCResp.new(status: ServingStatus::NOT_SERVING)
+ expect(got).to eq(want)
+ @srv.stop
+ t.join
+ end
+
+ it 'should fail on unknown services', server: true do
+ @srv.handle(subject)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ blk = proc do
+ stub = CheckerStub.new(@host, **@client_opts)
+ stub.check(HCReq.new(host: 'unknown', service: 'unknown'))
+ end
+ expected_msg = /#{StatusCodes::NOT_FOUND}/
+ expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+ @srv.stop
+ t.join
+ end
+ end
+end
diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb
index 270d2e97d3..c891c1bf5e 100644
--- a/src/ruby/spec/spec_helper.rb
+++ b/src/ruby/spec/spec_helper.rb
@@ -47,11 +47,23 @@ require 'rspec'
require 'logging'
require 'rspec/logging_helper'
+# GRPC is the general RPC module
+#
+# Configure its logging for fine-grained log control during test runs
+module GRPC
+ extend Logging.globally
+end
+Logging.logger.root.appenders = Logging.appenders.stdout
+Logging.logger.root.level = :info
+Logging.logger['GRPC'].level = :info
+Logging.logger['GRPC::ActiveCall'].level = :info
+Logging.logger['GRPC::BidiCall'].level = :info
+
# Configure RSpec to capture log messages for each test. The output from the
# logs will be stored in the @log_output variable. It is a StringIO instance.
RSpec.configure do |config|
include RSpec::LoggingHelper
- config.capture_log_messages
+ config.capture_log_messages # comment this out to see logs during test runs
end
RSpec::Expectations.configuration.warn_about_potential_false_positives = false