aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitmodules12
-rw-r--r--AUTHORS1
-rw-r--r--BUILD38
-rw-r--r--CMakeLists.txt218
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Makefile302
-rw-r--r--PYTHON-MANIFEST.in2
-rw-r--r--README.md20
-rw-r--r--WORKSPACE49
-rw-r--r--bazel/grpc_build_system.bzl4
-rw-r--r--bazel/grpc_deps.bzl49
-rw-r--r--build.yaml87
-rw-r--r--cmake/cares.cmake4
-rw-r--r--config.m412
-rw-r--r--config.w329
-rw-r--r--doc/connectivity-semantics-and-api.md11
-rw-r--r--doc/environment_variables.md10
-rw-r--r--doc/g_stands_for.md3
-rw-r--r--doc/grpc_release_schedule.md22
-rw-r--r--doc/naming.md4
-rw-r--r--doc/python/sphinx/conf.py105
-rw-r--r--doc/python/sphinx/glossary.rst16
-rw-r--r--doc/python/sphinx/grpc.rst169
-rw-r--r--doc/python/sphinx/grpc_channelz.rst12
-rw-r--r--doc/python/sphinx/grpc_health_checking.rst7
-rw-r--r--doc/python/sphinx/grpc_reflection.rst19
-rw-r--r--doc/python/sphinx/grpc_testing.rst7
-rw-r--r--doc/python/sphinx/index.rst25
-rw-r--r--examples/csharp/.gitignore2
-rw-r--r--examples/csharp/Helloworld/Greeter.sln2
-rw-r--r--examples/csharp/Helloworld/Greeter/Greeter.csproj17
-rw-r--r--examples/csharp/Helloworld/Greeter/Helloworld.cs312
-rw-r--r--examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs149
-rw-r--r--examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj8
-rw-r--r--examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj8
-rw-r--r--examples/csharp/Helloworld/README.md32
-rw-r--r--examples/csharp/Helloworld/generate_protos.bat28
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/Greeter.sln2
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj23
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs312
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs149
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config10
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj8
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config6
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj8
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config6
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/README.md27
-rw-r--r--examples/csharp/HelloworldLegacyCsproj/generate_protos.bat26
-rw-r--r--examples/csharp/RouteGuide/RouteGuide.sln2
-rw-r--r--examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs981
-rw-r--r--examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj21
-rw-r--r--examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs331
-rw-r--r--examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs2
-rw-r--r--examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj8
-rw-r--r--examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj8
-rw-r--r--examples/csharp/RouteGuide/generate_protos.bat28
-rw-r--r--examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj8
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld.podspec66
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj399
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h25
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m37
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json58
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json6
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard717
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements5
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Info.plist32
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/ViewController.h25
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/ViewController.m37
-rw-r--r--examples/objective-c/helloworld_macos/Podfile9
-rw-r--r--examples/objective-c/helloworld_macos/README.md6
-rw-r--r--examples/objective-c/helloworld_macos/main.m43
-rw-r--r--examples/python/helloworld/greeter_client.py2
-rw-r--r--examples/python/helloworld/greeter_client_with_options.py2
-rw-r--r--examples/python/helloworld/greeter_server.py2
-rw-r--r--examples/python/helloworld/greeter_server_with_reflection.py2
-rw-r--r--examples/python/interceptors/default_value/greeter_client.py2
-rw-r--r--examples/python/interceptors/headers/greeter_client.py2
-rw-r--r--examples/python/interceptors/headers/greeter_server.py2
-rw-r--r--examples/python/multiplex/multiplex_client.py2
-rw-r--r--examples/python/multiplex/multiplex_server.py2
-rw-r--r--examples/python/route_guide/route_guide_client.py2
-rw-r--r--examples/python/route_guide/route_guide_server.py2
-rw-r--r--gRPC-C++.podspec28
-rw-r--r--gRPC-Core.podspec28
-rw-r--r--gRPC-ProtoRPC.podspec2
-rw-r--r--gRPC-RxLibrary.podspec2
-rw-r--r--gRPC.podspec2
-rw-r--r--grpc.def1
-rw-r--r--grpc.gemspec17
-rw-r--r--grpc.gyp30
-rw-r--r--include/grpc/grpc.h3
-rw-r--r--include/grpc/impl/codegen/atm_gcc_sync.h2
-rw-r--r--include/grpc/impl/codegen/atm_windows.h2
-rw-r--r--include/grpc/impl/codegen/grpc_types.h7
-rw-r--r--include/grpc/impl/codegen/port_platform.h9
-rw-r--r--include/grpcpp/channel.h14
-rw-r--r--include/grpcpp/create_channel.h4
-rw-r--r--include/grpcpp/generic/generic_stub.h5
-rw-r--r--include/grpcpp/health_check_service_interface.h4
-rw-r--r--include/grpcpp/impl/codegen/async_stream.h34
-rw-r--r--include/grpcpp/impl/codegen/async_unary_call.h15
-rw-r--r--include/grpcpp/impl/codegen/byte_buffer.h18
-rw-r--r--include/grpcpp/impl/codegen/call.h687
-rw-r--r--include/grpcpp/impl/codegen/call_op_set.h919
-rw-r--r--include/grpcpp/impl/codegen/call_op_set_interface.h59
-rw-r--r--include/grpcpp/impl/codegen/callback_common.h81
-rw-r--r--include/grpcpp/impl/codegen/channel_interface.h31
-rw-r--r--include/grpcpp/impl/codegen/client_callback.h659
-rw-r--r--include/grpcpp/impl/codegen/client_context.h32
-rw-r--r--include/grpcpp/impl/codegen/client_interceptor.h135
-rw-r--r--include/grpcpp/impl/codegen/client_unary_call.h20
-rw-r--r--include/grpcpp/impl/codegen/completion_queue.h54
-rw-r--r--include/grpcpp/impl/codegen/core_codegen.h3
-rw-r--r--include/grpcpp/impl/codegen/core_codegen_interface.h12
-rw-r--r--include/grpcpp/impl/codegen/intercepted_channel.h80
-rw-r--r--include/grpcpp/impl/codegen/interceptor.h70
-rw-r--r--include/grpcpp/impl/codegen/interceptor_common.h458
-rw-r--r--include/grpcpp/impl/codegen/metadata_map.h21
-rw-r--r--include/grpcpp/impl/codegen/method_handler_impl.h83
-rw-r--r--include/grpcpp/impl/codegen/rpc_service_method.h74
-rw-r--r--include/grpcpp/impl/codegen/server_callback.h890
-rw-r--r--include/grpcpp/impl/codegen/server_context.h63
-rw-r--r--include/grpcpp/impl/codegen/server_interceptor.h118
-rw-r--r--include/grpcpp/impl/codegen/server_interface.h96
-rw-r--r--include/grpcpp/impl/codegen/service_type.h58
-rw-r--r--include/grpcpp/impl/codegen/sync_stream.h20
-rw-r--r--include/grpcpp/security/credentials.h12
-rw-r--r--include/grpcpp/server.h36
-rw-r--r--include/grpcpp/server_builder.h26
-rw-r--r--include/grpcpp/support/server_callback.h24
-rw-r--r--package.xml21
-rw-r--r--requirements.bazel.txt5
-rw-r--r--setup.cfg3
-rw-r--r--setup.py41
-rw-r--r--src/compiler/cpp_generator.cc325
-rw-r--r--src/compiler/csharp_generator.cc37
-rw-r--r--src/core/ext/filters/client_channel/client_channel.cc490
-rw-r--r--src/core/ext/filters/client_channel/health/health_check_client.cc18
-rw-r--r--src/core/ext/filters/client_channel/health/health_check_client.h7
-rw-r--r--src/core/ext/filters/client_channel/http_connect_handshaker.cc2
-rw-r--r--src/core/ext/filters/client_channel/http_proxy.cc2
-rw-r--r--src/core/ext/filters/client_channel/lb_policy.cc2
-rw-r--r--src/core/ext/filters/client_channel/lb_policy.h24
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc26
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc103
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc82
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc8
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/subchannel_list.h8
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds.cc458
-rw-r--r--src/core/ext/filters/client_channel/lb_policy_factory.h2
-rw-r--r--src/core/ext/filters/client_channel/lb_policy_registry.cc5
-rw-r--r--src/core/ext/filters/client_channel/lb_policy_registry.h4
-rw-r--r--src/core/ext/filters/client_channel/method_params.cc178
-rw-r--r--src/core/ext/filters/client_channel/method_params.h78
-rw-r--r--src/core/ext/filters/client_channel/parse_address.h2
-rw-r--r--src/core/ext/filters/client_channel/resolver.cc2
-rw-r--r--src/core/ext/filters/client_channel/resolver.h2
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc44
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc36
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h1
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc12
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h4
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc3
-rw-r--r--src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc17
-rw-r--r--src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h6
-rw-r--r--src/core/ext/filters/client_channel/resolver_factory.h2
-rw-r--r--src/core/ext/filters/client_channel/resolver_result_parsing.cc369
-rw-r--r--src/core/ext/filters/client_channel/resolver_result_parsing.h146
-rw-r--r--src/core/ext/filters/client_channel/subchannel.cc32
-rw-r--r--src/core/ext/filters/client_channel/subchannel.h2
-rw-r--r--src/core/ext/filters/client_channel/subchannel_index.cc47
-rw-r--r--src/core/ext/filters/deadline/deadline_filter.cc42
-rw-r--r--src/core/ext/filters/deadline/deadline_filter.h22
-rw-r--r--src/core/ext/filters/http/client/http_client_filter.cc48
-rw-r--r--src/core/ext/filters/http/message_compress/message_compress_filter.cc44
-rw-r--r--src/core/ext/filters/http/server/http_server_filter.cc51
-rw-r--r--src/core/ext/filters/load_reporting/server_load_reporting_filter.cc2
-rw-r--r--src/core/ext/filters/message_size/message_size_filter.cc95
-rw-r--r--src/core/ext/transport/chttp2/client/chttp2_connector.cc5
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc2
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.cc39
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc2
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.cc400
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.h7
-rw-r--r--src/core/ext/transport/chttp2/transport/context_list.cc51
-rw-r--r--src/core/ext/transport/chttp2/transport/context_list.h72
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.cc14
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h22
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.cc2
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.cc53
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.cc12
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.h21
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h252
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.cc5
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.cc153
-rw-r--r--src/core/ext/transport/inproc/inproc_transport.cc578
-rw-r--r--src/core/lib/channel/channel_stack.cc9
-rw-r--r--src/core/lib/channel/channel_stack.h8
-rw-r--r--src/core/lib/channel/channel_stack_builder.cc16
-rw-r--r--src/core/lib/channel/channel_stack_builder.h8
-rw-r--r--src/core/lib/channel/channelz.cc84
-rw-r--r--src/core/lib/channel/channelz.h16
-rw-r--r--src/core/lib/channel/channelz_registry.cc29
-rw-r--r--src/core/lib/channel/channelz_registry.h6
-rw-r--r--src/core/lib/channel/context.h8
-rw-r--r--src/core/lib/debug/trace.cc3
-rw-r--r--src/core/lib/debug/trace.h8
-rw-r--r--src/core/lib/gpr/arena.cc121
-rw-r--r--src/core/lib/gpr/arena.h2
-rw-r--r--src/core/lib/gprpp/inlined_vector.h44
-rw-r--r--src/core/lib/gprpp/orphanable.h100
-rw-r--r--src/core/lib/gprpp/ref_counted.h230
-rw-r--r--src/core/lib/gprpp/ref_counted_ptr.h42
-rw-r--r--src/core/lib/iomgr/buffer_list.cc21
-rw-r--r--src/core/lib/iomgr/buffer_list.h13
-rw-r--r--src/core/lib/iomgr/call_combiner.cc54
-rw-r--r--src/core/lib/iomgr/call_combiner.h35
-rw-r--r--src/core/lib/iomgr/closure.h1
-rw-r--r--src/core/lib/iomgr/dynamic_annotations.h67
-rw-r--r--src/core/lib/iomgr/endpoint.cc4
-rw-r--r--src/core/lib/iomgr/endpoint.h3
-rw-r--r--src/core/lib/iomgr/endpoint_cfstream.cc5
-rw-r--r--src/core/lib/iomgr/endpoint_pair_posix.cc4
-rw-r--r--src/core/lib/iomgr/ev_epoll1_linux.cc4
-rw-r--r--src/core/lib/iomgr/ev_epollex_linux.cc4
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.cc4
-rw-r--r--src/core/lib/iomgr/ev_posix.cc22
-rw-r--r--src/core/lib/iomgr/ev_posix.h10
-rw-r--r--src/core/lib/iomgr/fork_posix.cc2
-rw-r--r--src/core/lib/iomgr/internal_errqueue.cc39
-rw-r--r--src/core/lib/iomgr/internal_errqueue.h8
-rw-r--r--src/core/lib/iomgr/iomgr.cc7
-rw-r--r--src/core/lib/iomgr/iomgr.h4
-rw-r--r--src/core/lib/iomgr/iomgr_custom.cc4
-rw-r--r--src/core/lib/iomgr/iomgr_internal.cc4
-rw-r--r--src/core/lib/iomgr/iomgr_internal.h4
-rw-r--r--src/core/lib/iomgr/iomgr_posix.cc7
-rw-r--r--src/core/lib/iomgr/iomgr_posix_cfstream.cc7
-rw-r--r--src/core/lib/iomgr/iomgr_windows.cc5
-rw-r--r--src/core/lib/iomgr/polling_entity.h8
-rw-r--r--src/core/lib/iomgr/port.h3
-rw-r--r--src/core/lib/iomgr/resolve_address.h2
-rw-r--r--src/core/lib/iomgr/resource_quota.cc74
-rw-r--r--src/core/lib/iomgr/resource_quota.h27
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.cc11
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.cc2
-rw-r--r--src/core/lib/iomgr/tcp_custom.cc5
-rw-r--r--src/core/lib/iomgr/tcp_posix.cc105
-rw-r--r--src/core/lib/iomgr/tcp_windows.cc99
-rw-r--r--src/core/lib/security/context/security_context.cc33
-rw-r--r--src/core/lib/security/context/security_context.h46
-rw-r--r--src/core/lib/security/credentials/credentials.h4
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.cc221
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.h5
-rw-r--r--src/core/lib/security/transport/client_auth_filter.cc44
-rw-r--r--src/core/lib/security/transport/secure_endpoint.cc100
-rw-r--r--src/core/lib/security/transport/security_handshaker.cc3
-rw-r--r--src/core/lib/security/transport/server_auth_filter.cc70
-rw-r--r--src/core/lib/surface/call.cc180
-rw-r--r--src/core/lib/surface/call.h4
-rw-r--r--src/core/lib/surface/channel.cc26
-rw-r--r--src/core/lib/surface/channel.h3
-rw-r--r--src/core/lib/surface/completion_queue.cc2
-rw-r--r--src/core/lib/surface/init.cc2
-rw-r--r--src/core/lib/surface/server.cc248
-rw-r--r--src/core/lib/surface/server.h13
-rw-r--r--src/core/lib/surface/version.cc2
-rw-r--r--src/core/lib/transport/metadata_batch.h6
-rw-r--r--src/core/lib/transport/static_metadata.cc449
-rw-r--r--src/core/lib/transport/static_metadata.h146
-rw-r--r--src/core/lib/transport/transport.cc3
-rw-r--r--src/core/lib/transport/transport.h74
-rw-r--r--src/core/lib/uri/uri_parser.cc (renamed from src/core/ext/filters/client_channel/uri_parser.cc)2
-rw-r--r--src/core/lib/uri/uri_parser.h (renamed from src/core/ext/filters/client_channel/uri_parser.h)6
-rw-r--r--src/core/plugin_registry/grpc_cronet_plugin_registry.cc4
-rw-r--r--src/core/plugin_registry/grpc_plugin_registry.cc4
-rw-r--r--src/core/tsi/alts/handshaker/alts_handshaker_client.cc440
-rw-r--r--src/core/tsi/alts/handshaker/alts_handshaker_client.h82
-rw-r--r--src/core/tsi/alts/handshaker/alts_shared_resource.cc83
-rw-r--r--src/core/tsi/alts/handshaker/alts_shared_resource.h73
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_event.cc75
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_event.h93
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc294
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker.h50
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h48
-rw-r--r--src/core/tsi/alts_transport_security.cc65
-rw-r--r--src/core/tsi/alts_transport_security.h47
-rw-r--r--src/core/tsi/transport_security.cc2
-rw-r--r--src/cpp/client/channel_cc.cc45
-rw-r--r--src/cpp/client/client_context.cc21
-rw-r--r--src/cpp/client/client_interceptor.cc34
-rw-r--r--src/cpp/client/create_channel.cc36
-rw-r--r--src/cpp/client/create_channel_internal.cc4
-rw-r--r--src/cpp/client/create_channel_internal.h4
-rw-r--r--src/cpp/client/create_channel_posix.cc10
-rw-r--r--src/cpp/client/cronet_credentials.cc9
-rw-r--r--src/cpp/client/generic_stub.cc9
-rw-r--r--src/cpp/client/insecure_credentials.cc9
-rw-r--r--src/cpp/client/secure_credentials.cc16
-rw-r--r--src/cpp/client/secure_credentials.h4
-rw-r--r--src/cpp/common/completion_queue_cc.cc10
-rw-r--r--src/cpp/common/core_codegen.cc7
-rw-r--r--src/cpp/common/version_cc.cc2
-rw-r--r--src/cpp/ext/filters/census/context.cc12
-rw-r--r--src/cpp/server/channelz/channelz_service.cc17
-rw-r--r--src/cpp/server/channelz/channelz_service.h4
-rw-r--r--src/cpp/server/health/default_health_check_service.cc19
-rw-r--r--src/cpp/server/health/default_health_check_service.h3
-rw-r--r--src/cpp/server/secure_server_credentials.cc7
-rw-r--r--src/cpp/server/server_builder.cc38
-rw-r--r--src/cpp/server/server_cc.cc511
-rw-r--r--src/cpp/server/server_context.cc246
-rw-r--r--src/csharp/BUILD-INTEGRATION.md357
-rw-r--r--src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs2
-rwxr-xr-xsrc/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj2
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallerTest.cs7
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitMain.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs4
-rw-r--r--src/csharp/Grpc.Core/DeserializationContext.cs7
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs27
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs66
-rw-r--r--src/csharp/Grpc.Core/Internal/DefaultSerializationContext.cs62
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeExtension.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs16
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs67
-rw-r--r--src/csharp/Grpc.Core/SerializationContext.cs7
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs8
-rw-r--r--src/csharp/Grpc.Core/ServiceBinderBase.cs101
-rwxr-xr-xsrc/csharp/Grpc.Core/Version.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rwxr-xr-xsrc/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj2
-rwxr-xr-xsrc/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj2
-rwxr-xr-xsrc/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj2
-rw-r--r--src/csharp/Grpc.Examples.Tests/NUnitMain.cs6
-rwxr-xr-xsrc/csharp/Grpc.Examples/Grpc.Examples.csproj2
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs12
-rwxr-xr-xsrc/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs6
-rw-r--r--src/csharp/Grpc.HealthCheck/Health.cs20
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs135
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj2
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj2
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj4
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs13
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Control.cs144
-rw-r--r--src/csharp/Grpc.IntegrationTesting/EmptyServiceGrpc.cs8
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/NUnitMain.cs6
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs9
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs35
-rw-r--r--src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs12
-rw-r--r--src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj2
-rwxr-xr-xsrc/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj2
-rw-r--r--src/csharp/Grpc.Reflection.Tests/NUnitMain.cs6
-rw-r--r--src/csharp/Grpc.Reflection/ReflectionGrpc.cs9
-rw-r--r--src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj2
-rw-r--r--src/csharp/Grpc.Tools.Tests/NUnitMain.cs4
-rw-r--r--src/csharp/README.md1
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat2
-rw-r--r--src/csharp/build_unitypackage.bat2
-rw-r--r--src/csharp/doc/integration.md-fig.1-classic.pngbin0 -> 15266 bytes
-rw-r--r--src/csharp/doc/integration.md-fig.2-sdk.pngbin0 -> 15863 bytes
-rw-r--r--src/objective-c/!ProtoCompiler-gRPCPlugin.podspec2
-rw-r--r--src/objective-c/GRPCClient/private/version.h2
-rw-r--r--src/objective-c/tests/version.h2
-rw-r--r--src/php/composer.json2
-rw-r--r--src/php/ext/grpc/channel.c2
-rw-r--r--src/php/ext/grpc/channel.h3
-rwxr-xr-xsrc/php/ext/grpc/config.m42
-rw-r--r--src/php/ext/grpc/php_grpc.c122
-rw-r--r--src/php/ext/grpc/version.h2
-rw-r--r--src/proto/grpc/channelz/BUILD7
-rw-r--r--src/proto/grpc/channelz/channelz.proto13
-rw-r--r--src/proto/grpc/health/v1/BUILD1
-rw-r--r--src/proto/grpc/reflection/v1alpha/BUILD8
-rw-r--r--src/proto/grpc/testing/BUILD43
-rw-r--r--src/proto/grpc/testing/compiler_test.proto3
-rw-r--r--src/proto/grpc/testing/control.proto1
-rw-r--r--src/proto/grpc/testing/echo.proto4
-rw-r--r--src/proto/grpc/testing/proto2/BUILD.bazel30
-rw-r--r--src/proto/grpc/testing/simple_messages.proto24
-rw-r--r--src/python/.gitignore1
-rw-r--r--src/python/grpcio/_parallel_compile_patch.py63
-rw-r--r--src/python/grpcio/commands.py69
-rw-r--r--src/python/grpcio/grpc/BUILD.bazel1
-rw-r--r--src/python/grpcio/grpc/__init__.py130
-rw-r--r--src/python/grpcio/grpc/_channel.py128
-rw-r--r--src/python/grpcio/grpc/_common.py14
-rw-r--r--src/python/grpcio/grpc/_cython/BUILD.bazel1
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi69
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi12
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi16
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi21
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi1
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/metadata.pxd.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi10
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi36
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi36
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi8
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi1
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/time.pxd.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/time.pyx.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pyx2
-rw-r--r--src/python/grpcio/grpc/_grpcio_metadata.py2
-rw-r--r--src/python/grpcio/grpc/_interceptor.py139
-rw-r--r--src/python/grpcio/grpc/_plugin_wrapping.py1
-rw-r--r--src/python/grpcio/grpc/_server.py1
-rw-r--r--src/python/grpcio/grpc/beta/BUILD.bazel58
-rw-r--r--src/python/grpcio/grpc/framework/foundation/callable_util.py1
-rw-r--r--src/python/grpcio/grpc/framework/foundation/logging_pool.py1
-rw-r--r--src/python/grpcio/grpc/framework/foundation/stream_util.py1
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py8
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio_channelz/.gitignore6
-rw-r--r--src/python/grpcio_channelz/MANIFEST.in4
-rw-r--r--src/python/grpcio_channelz/README.rst9
-rw-r--r--src/python/grpcio_channelz/channelz_commands.py67
-rw-r--r--src/python/grpcio_channelz/grpc_channelz/__init__.py13
-rw-r--r--src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel38
-rw-r--r--src/python/grpcio_channelz/grpc_channelz/v1/__init__.py13
-rw-r--r--src/python/grpcio_channelz/grpc_channelz/v1/channelz.py141
-rw-r--r--src/python/grpcio_channelz/grpc_version.py17
-rw-r--r--src/python/grpcio_channelz/setup.py96
-rw-r--r--src/python/grpcio_health_checking/MANIFEST.in1
-rw-r--r--src/python/grpcio_health_checking/grpc_version.py2
-rw-r--r--src/python/grpcio_health_checking/health_commands.py8
-rw-r--r--src/python/grpcio_health_checking/setup.py2
-rw-r--r--src/python/grpcio_reflection/MANIFEST.in1
-rw-r--r--src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel34
-rw-r--r--src/python/grpcio_reflection/grpc_version.py2
-rw-r--r--src/python/grpcio_reflection/reflection_commands.py8
-rw-r--r--src/python/grpcio_reflection/setup.py2
-rw-r--r--src/python/grpcio_testing/MANIFEST.in1
-rw-r--r--src/python/grpcio_testing/grpc_version.py2
-rw-r--r--src/python/grpcio_testing/setup.py33
-rw-r--r--src/python/grpcio_testing/testing_commands.py39
-rw-r--r--src/python/grpcio_tests/commands.py7
-rw-r--r--src/python/grpcio_tests/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/setup.py1
-rw-r--r--src/python/grpcio_tests/tests/_sanity/_sanity_test.py4
-rw-r--r--src/python/grpcio_tests/tests/channelz/BUILD.bazel15
-rw-r--r--src/python/grpcio_tests/tests/channelz/__init__.py13
-rw-r--r--src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py470
-rw-r--r--src/python/grpcio_tests/tests/interop/BUILD.bazel101
-rw-r--r--src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel9
-rw-r--r--src/python/grpcio_tests/tests/interop/methods.py30
-rw-r--r--src/python/grpcio_tests/tests/interop/resources.py11
-rw-r--r--src/python/grpcio_tests/tests/interop/server.py2
-rw-r--r--src/python/grpcio_tests/tests/qps/worker_server.py4
-rw-r--r--src/python/grpcio_tests/tests/reflection/BUILD.bazel21
-rw-r--r--src/python/grpcio_tests/tests/tests.json4
-rw-r--r--src/python/grpcio_tests/tests/unit/BUILD.bazel1
-rw-r--r--src/python/grpcio_tests/tests/unit/_api_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_auth_context_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_auth_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_args_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_close_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_compression_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_credentials_test.py13
-rw-r--r--src/python/grpcio_tests/tests/unit/_empty_message_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py86
-rw-r--r--src/python/grpcio_tests/tests/unit/_exit_scenarios.py4
-rw-r--r--src/python/grpcio_tests/tests/unit/_exit_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_interceptor_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py5
-rw-r--r--src/python/grpcio_tests/tests/unit/_invocation_defects_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_logging_test.py80
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_flags_test.py251
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_reconnect_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_rpc_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py53
-rw-r--r--src/python/grpcio_tests/tests/unit/_server_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_session_cache_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/beta/BUILD.bazel75
-rw-r--r--src/python/grpcio_tests/tests/unit/resources.py35
-rw-r--r--src/python/grpcio_tests/tests/unit/test_common.py26
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h3
-rw-r--r--src/ruby/lib/grpc/generic/service.rb2
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rw-r--r--src/ruby/pb/grpc/health/checker.rb5
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb22
-rw-r--r--src/ruby/spec/support/services.rb1
-rw-r--r--src/ruby/tools/version.rb2
-rw-r--r--templates/Makefile.template2
-rw-r--r--templates/config.m4.template3
-rw-r--r--templates/gRPC-C++.podspec.template13
-rw-r--r--templates/src/python/grpcio_channelz/grpc_version.py.template19
-rw-r--r--templates/tools/dockerfile/bazel.include7
-rw-r--r--templates/tools/dockerfile/csharp_deps.include25
-rw-r--r--templates/tools/dockerfile/csharp_dotnetcli_deps.include26
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template2
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template2
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template14
-rw-r--r--templates/tools/dockerfile/test/csharp_stretch_x64/Dockerfile.template (renamed from templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template)4
-rw-r--r--templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template41
-rw-r--r--templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template3
-rw-r--r--test/core/avl/avl_test.cc2
-rw-r--r--test/core/backoff/backoff_test.cc2
-rw-r--r--test/core/bad_client/bad_client.cc2
-rw-r--r--test/core/bad_client/tests/badreq.cc2
-rw-r--r--test/core/bad_client/tests/connection_prefix.cc2
-rw-r--r--test/core/bad_client/tests/duplicate_header.cc2
-rw-r--r--test/core/bad_client/tests/head_of_line_blocking.cc2
-rw-r--r--test/core/bad_client/tests/headers.cc2
-rw-r--r--test/core/bad_client/tests/initial_settings_frame.cc2
-rw-r--r--test/core/bad_client/tests/large_metadata.cc2
-rw-r--r--test/core/bad_client/tests/server_registered_method.cc2
-rw-r--r--test/core/bad_client/tests/simple_request.cc2
-rw-r--r--test/core/bad_client/tests/unknown_frame.cc2
-rw-r--r--test/core/bad_client/tests/window_overflow.cc2
-rw-r--r--test/core/channel/channel_args_test.cc2
-rw-r--r--test/core/channel/channel_stack_builder_test.cc2
-rw-r--r--test/core/channel/channel_stack_test.cc2
-rw-r--r--test/core/channel/channel_trace_test.cc2
-rw-r--r--test/core/channel/channelz_registry_test.cc2
-rw-r--r--test/core/channel/channelz_test.cc7
-rw-r--r--test/core/channel/minimal_stack_is_minimal_test.cc2
-rw-r--r--test/core/client_channel/parse_address_test.cc2
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc4
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc8
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_test.cc2
-rw-r--r--test/core/client_channel/resolvers/fake_resolver_test.cc2
-rw-r--r--test/core/client_channel/resolvers/sockaddr_resolver_test.cc2
-rw-r--r--test/core/client_channel/retry_throttle_test.cc2
-rw-r--r--test/core/client_channel/uri_fuzzer_test.cc2
-rw-r--r--test/core/client_channel/uri_parser_test.cc4
-rw-r--r--test/core/compression/algorithm_test.cc2
-rw-r--r--test/core/compression/message_compress_test.cc2
-rw-r--r--test/core/debug/BUILD34
-rw-r--r--test/core/end2end/bad_server_response_test.cc2
-rw-r--r--test/core/end2end/connection_refused_test.cc2
-rw-r--r--test/core/end2end/dualstack_socket_test.cc2
-rw-r--r--test/core/end2end/fixtures/h2_census.cc2
-rw-r--r--test/core/end2end/fixtures/h2_compress.cc2
-rw-r--r--test/core/end2end/fixtures/h2_fakesec.cc2
-rw-r--r--test/core/end2end/fixtures/h2_fd.cc2
-rw-r--r--test/core/end2end/fixtures/h2_full+pipe.cc2
-rw-r--r--test/core/end2end/fixtures/h2_full+trace.cc2
-rw-r--r--test/core/end2end/fixtures/h2_full+workarounds.cc2
-rw-r--r--test/core/end2end/fixtures/h2_full.cc2
-rw-r--r--test/core/end2end/fixtures/h2_http_proxy.cc2
-rw-r--r--test/core/end2end/fixtures/h2_local.cc2
-rw-r--r--test/core/end2end/fixtures/h2_oauth2.cc2
-rw-r--r--test/core/end2end/fixtures/h2_proxy.cc2
-rw-r--r--test/core/end2end/fixtures/h2_sockpair+trace.cc4
-rw-r--r--test/core/end2end/fixtures/h2_sockpair.cc4
-rw-r--r--test/core/end2end/fixtures/h2_sockpair_1byte.cc4
-rw-r--r--test/core/end2end/fixtures/h2_ssl.cc2
-rw-r--r--test/core/end2end/fixtures/h2_ssl_proxy.cc2
-rw-r--r--test/core/end2end/fixtures/h2_uds.cc2
-rw-r--r--test/core/end2end/fixtures/inproc.cc2
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer.cc4
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary1
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer.cc2
-rw-r--r--test/core/end2end/goaway_server_test.cc8
-rw-r--r--test/core/end2end/h2_ssl_cert_test.cc2
-rw-r--r--test/core/end2end/h2_ssl_session_reuse_test.cc2
-rw-r--r--test/core/end2end/inproc_callback_test.cc2
-rw-r--r--test/core/end2end/invalid_call_argument_test.cc2
-rw-r--r--test/core/end2end/multiple_server_queues_test.cc2
-rw-r--r--test/core/end2end/no_server_test.cc2
-rw-r--r--test/core/end2end/tests/channelz.cc7
-rw-r--r--test/core/end2end/tests/streaming_error_response.cc31
-rw-r--r--test/core/fling/client.cc6
-rw-r--r--test/core/gpr/BUILD2
-rw-r--r--test/core/gpr/alloc_test.cc2
-rw-r--r--test/core/gpr/arena_test.cc2
-rw-r--r--test/core/gpr/cpu_test.cc2
-rw-r--r--test/core/gpr/env_test.cc2
-rw-r--r--test/core/gpr/host_port_test.cc2
-rw-r--r--test/core/gpr/log_test.cc2
-rw-r--r--test/core/gpr/mpscq_test.cc2
-rw-r--r--test/core/gpr/murmur_hash_test.cc2
-rw-r--r--test/core/gpr/spinlock_test.cc2
-rw-r--r--test/core/gpr/string_test.cc2
-rw-r--r--test/core/gpr/sync_test.cc2
-rw-r--r--test/core/gpr/time_test.cc2
-rw-r--r--test/core/gpr/tls_test.cc2
-rw-r--r--test/core/gpr/useful_test.cc2
-rw-r--r--test/core/gprpp/fork_test.cc2
-rw-r--r--test/core/gprpp/inlined_vector_test.cc166
-rw-r--r--test/core/gprpp/manual_constructor_test.cc2
-rw-r--r--test/core/gprpp/memory_test.cc2
-rw-r--r--test/core/gprpp/orphanable_test.cc6
-rw-r--r--test/core/gprpp/ref_counted_ptr_test.cc6
-rw-r--r--test/core/gprpp/ref_counted_test.cc52
-rw-r--r--test/core/gprpp/thd_test.cc2
-rw-r--r--test/core/http/format_request_test.cc2
-rw-r--r--test/core/http/httpcli_test.cc2
-rw-r--r--test/core/http/httpscli_test.cc2
-rw-r--r--test/core/http/parser_test.cc2
-rw-r--r--test/core/iomgr/BUILD2
-rw-r--r--test/core/iomgr/buffer_list_test.cc6
-rw-r--r--test/core/iomgr/combiner_test.cc2
-rw-r--r--test/core/iomgr/endpoint_pair_test.cc2
-rw-r--r--test/core/iomgr/error_test.cc2
-rw-r--r--test/core/iomgr/ev_epollex_linux_test.cc2
-rw-r--r--test/core/iomgr/fd_conservation_posix_test.cc2
-rw-r--r--test/core/iomgr/fd_posix_test.cc2
-rw-r--r--test/core/iomgr/grpc_ipv6_loopback_available_test.cc2
-rw-r--r--test/core/iomgr/load_file_test.cc2
-rw-r--r--test/core/iomgr/resolve_address_posix_test.cc2
-rw-r--r--test/core/iomgr/resolve_address_test.cc2
-rw-r--r--test/core/iomgr/resource_quota_test.cc2
-rw-r--r--test/core/iomgr/sockaddr_utils_test.cc2
-rw-r--r--test/core/iomgr/socket_utils_test.cc2
-rw-r--r--test/core/iomgr/tcp_client_posix_test.cc2
-rw-r--r--test/core/iomgr/tcp_client_uv_test.cc2
-rw-r--r--test/core/iomgr/tcp_posix_test.cc2
-rw-r--r--test/core/iomgr/tcp_server_posix_test.cc2
-rw-r--r--test/core/iomgr/tcp_server_uv_test.cc2
-rw-r--r--test/core/iomgr/time_averaged_stats_test.cc2
-rw-r--r--test/core/iomgr/timer_heap_test.cc2
-rw-r--r--test/core/iomgr/timer_list_test.cc4
-rw-r--r--test/core/iomgr/udp_server_test.cc2
-rw-r--r--test/core/json/json_rewrite_test.cc2
-rw-r--r--test/core/json/json_stream_error_test.cc2
-rw-r--r--test/core/json/json_test.cc2
-rw-r--r--test/core/memory_usage/BUILD60
-rw-r--r--test/core/memory_usage/client.cc6
-rw-r--r--test/core/memory_usage/server.cc4
-rw-r--r--test/core/security/auth_context_test.cc2
-rw-r--r--test/core/security/credentials_test.cc89
-rw-r--r--test/core/security/json_token_test.cc2
-rw-r--r--test/core/security/jwt_verifier_test.cc2
-rw-r--r--test/core/security/linux_system_roots_test.cc2
-rw-r--r--test/core/security/secure_endpoint_test.cc2
-rw-r--r--test/core/security/security_connector_test.cc2
-rw-r--r--test/core/security/ssl_credentials_test.cc2
-rw-r--r--test/core/slice/b64_test.cc2
-rw-r--r--test/core/slice/percent_encoding_test.cc2
-rw-r--r--test/core/slice/slice_buffer_test.cc2
-rw-r--r--test/core/slice/slice_hash_table_test.cc2
-rw-r--r--test/core/slice/slice_string_helpers_test.cc2
-rw-r--r--test/core/slice/slice_test.cc2
-rw-r--r--test/core/slice/slice_weak_hash_table_test.cc2
-rw-r--r--test/core/surface/byte_buffer_reader_test.cc2
-rw-r--r--test/core/surface/channel_create_test.cc2
-rw-r--r--test/core/surface/completion_queue_test.cc2
-rw-r--r--test/core/surface/completion_queue_threading_test.cc2
-rw-r--r--test/core/surface/concurrent_connectivity_test.cc2
-rw-r--r--test/core/surface/init_test.cc2
-rw-r--r--test/core/surface/lame_client_test.cc2
-rw-r--r--test/core/surface/num_external_connectivity_watchers_test.cc2
-rw-r--r--test/core/surface/public_headers_must_be_c89.c1
-rw-r--r--test/core/surface/secure_channel_create_test.cc2
-rw-r--r--test/core/surface/sequential_connectivity_test.cc2
-rw-r--r--test/core/surface/server_chttp2_test.cc2
-rw-r--r--test/core/surface/server_test.cc2
-rw-r--r--test/core/transport/bdp_estimator_test.cc2
-rw-r--r--test/core/transport/byte_stream_test.cc2
-rw-r--r--test/core/transport/chttp2/BUILD16
-rw-r--r--test/core/transport/chttp2/alpn_test.cc2
-rw-r--r--test/core/transport/chttp2/context_list_test.cc102
-rw-r--r--test/core/transport/chttp2/hpack_encoder_test.cc2
-rw-r--r--test/core/transport/chttp2/hpack_parser_test.cc2
-rw-r--r--test/core/transport/chttp2/hpack_table_test.cc2
-rw-r--r--test/core/transport/chttp2/settings_timeout_test.cc2
-rw-r--r--test/core/transport/chttp2/stream_map_test.cc2
-rw-r--r--test/core/transport/chttp2/varint_test.cc2
-rw-r--r--test/core/transport/connectivity_state_test.cc2
-rw-r--r--test/core/transport/metadata_test.cc2
-rw-r--r--test/core/transport/pid_controller_test.cc2
-rw-r--r--test/core/transport/status_conversion_test.cc2
-rw-r--r--test/core/transport/stream_owned_slice_test.cc2
-rw-r--r--test/core/transport/timeout_encoding_test.cc2
-rw-r--r--test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc225
-rw-r--r--test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc305
-rw-r--r--test/core/tsi/fake_transport_security_test.cc2
-rw-r--r--test/core/tsi/ssl_session_cache_test.cc2
-rw-r--r--test/core/tsi/ssl_transport_security_test.cc2
-rw-r--r--test/core/tsi/transport_security_test.cc2
-rw-r--r--test/core/util/cmdline_test.cc2
-rw-r--r--test/core/util/fuzzer_corpus_test.cc2
-rw-r--r--test/core/util/mock_endpoint.cc25
-rw-r--r--test/core/util/passthru_endpoint.cc3
-rw-r--r--test/core/util/test_config.cc12
-rw-r--r--test/core/util/test_config.h15
-rw-r--r--test/core/util/trickle_endpoint.cc5
-rw-r--r--test/cpp/client/client_channel_stress_test.cc2
-rw-r--r--test/cpp/codegen/compiler_test_golden242
-rw-r--r--test/cpp/common/alarm_test.cc2
-rw-r--r--test/cpp/end2end/BUILD69
-rw-r--r--test/cpp/end2end/async_end2end_test.cc2
-rw-r--r--test/cpp/end2end/channelz_service_test.cc49
-rw-r--r--test/cpp/end2end/client_callback_end2end_test.cc324
-rw-r--r--test/cpp/end2end/client_crash_test.cc2
-rw-r--r--test/cpp/end2end/client_interceptors_end2end_test.cc651
-rw-r--r--test/cpp/end2end/client_lb_end2end_test.cc143
-rw-r--r--test/cpp/end2end/end2end_test.cc160
-rw-r--r--test/cpp/end2end/exception_test.cc2
-rw-r--r--test/cpp/end2end/filter_end2end_test.cc2
-rw-r--r--test/cpp/end2end/generic_end2end_test.cc2
-rw-r--r--test/cpp/end2end/grpclb_end2end_test.cc18
-rw-r--r--test/cpp/end2end/health_service_end2end_test.cc151
-rw-r--r--test/cpp/end2end/hybrid_end2end_test.cc2
-rw-r--r--test/cpp/end2end/interceptors_util.cc149
-rw-r--r--test/cpp/end2end/interceptors_util.h278
-rw-r--r--test/cpp/end2end/mock_test.cc2
-rw-r--r--test/cpp/end2end/nonblocking_test.cc2
-rw-r--r--test/cpp/end2end/proto_server_reflection_test.cc2
-rw-r--r--test/cpp/end2end/raw_end2end_test.cc2
-rw-r--r--test/cpp/end2end/server_builder_plugin_test.cc2
-rw-r--r--test/cpp/end2end/server_crash_test.cc2
-rw-r--r--test/cpp/end2end/server_early_return_test.cc2
-rw-r--r--test/cpp/end2end/server_interceptors_end2end_test.cc610
-rw-r--r--test/cpp/end2end/shutdown_test.cc2
-rw-r--r--test/cpp/end2end/streaming_throughput_test.cc2
-rw-r--r--test/cpp/end2end/test_health_check_service_impl.cc97
-rw-r--r--test/cpp/end2end/test_health_check_service_impl.h58
-rw-r--r--test/cpp/end2end/test_service_impl.cc476
-rw-r--r--test/cpp/end2end/test_service_impl.h51
-rw-r--r--test/cpp/end2end/thread_stress_test.cc2
-rw-r--r--test/cpp/ext/filters/census/stats_plugin_end2end_test.cc2
-rw-r--r--test/cpp/interop/client_helper.h2
-rw-r--r--test/cpp/interop/interop_client.cc4
-rw-r--r--test/cpp/interop/stress_interop_client.cc2
-rw-r--r--test/cpp/microbenchmarks/bm_call_create.cc5
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_hpack.cc4
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_transport.cc18
-rw-r--r--test/cpp/microbenchmarks/bm_cq_multiple_threads.cc1
-rw-r--r--test/cpp/microbenchmarks/fullstack_fixtures.h7
-rw-r--r--test/cpp/naming/address_sorting_test.cc2
-rw-r--r--test/cpp/naming/cancel_ares_query_test.cc61
-rw-r--r--test/cpp/naming/resolver_component_test.cc2
-rw-r--r--test/cpp/performance/writes_per_rpc_test.cc9
-rw-r--r--test/cpp/qps/BUILD3
-rw-r--r--test/cpp/qps/client.h8
-rw-r--r--test/cpp/qps/driver.cc36
-rw-r--r--test/cpp/qps/driver.h9
-rw-r--r--test/cpp/qps/inproc_sync_unary_ping_pong_test.cc2
-rw-r--r--test/cpp/qps/qps_json_driver.cc111
-rw-r--r--test/cpp/qps/qps_openloop_test.cc2
-rw-r--r--test/cpp/qps/qps_worker.cc2
-rw-r--r--test/cpp/qps/secure_sync_unary_ping_pong_test.cc2
-rw-r--r--test/cpp/qps/server.h1
-rw-r--r--test/cpp/qps/server_async.cc1
-rw-r--r--test/cpp/qps/server_callback.cc96
-rw-r--r--test/cpp/server/load_reporter/get_cpu_stats_test.cc2
-rw-r--r--test/cpp/server/load_reporter/load_data_store_test.cc2
-rw-r--r--test/cpp/server/load_reporter/load_reporter_test.cc2
-rw-r--r--test/cpp/util/BUILD3
-rw-r--r--test/cpp/util/byte_buffer_proto_helper.h7
-rw-r--r--test/cpp/util/channel_trace_proto_helper.cc5
-rw-r--r--test/cpp/util/channel_trace_proto_helper.h1
-rw-r--r--test/cpp/util/cli_call_test.cc2
-rw-r--r--test/cpp/util/grpc_tool_test.cc5
m---------third_party/boringssl-with-bazel0
m---------third_party/data-plane-api0
m---------third_party/googleapis0
m---------third_party/protoc-gen-validate0
-rw-r--r--third_party/toolchains/BUILD51
-rw-r--r--third_party/toolchains/RBE_USE_MACHINE_TYPE_LARGE1
-rw-r--r--third_party/toolchains/machine_size/BUILD31
m---------third_party/upb0
-rw-r--r--tools/bazel.rc11
-rwxr-xr-xtools/codegen/core/gen_static_metadata.py1
-rwxr-xr-xtools/distrib/pylint_code.sh1
-rwxr-xr-xtools/distrib/python/docgen.py39
-rw-r--r--tools/distrib/python/grpcio_tools/MANIFEST.in1
-rw-r--r--tools/distrib/python/grpcio_tools/_parallel_compile_patch.py63
-rw-r--r--tools/distrib/python/grpcio_tools/grpc_version.py2
-rw-r--r--tools/distrib/python/grpcio_tools/setup.py3
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile45
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile45
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh6
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_php/build_interop.sh9
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh9
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_python/Dockerfile33
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_python/build_interop.sh4
-rw-r--r--tools/dockerfile/test/bazel/Dockerfile7
-rw-r--r--tools/dockerfile/test/csharp_stretch_x64/Dockerfile (renamed from tools/dockerfile/test/csharp_jessie_x64/Dockerfile)47
-rw-r--r--tools/dockerfile/test/multilang_jessie_x64/Dockerfile170
-rw-r--r--tools/dockerfile/test/python_alpine_x64/Dockerfile8
-rw-r--r--tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile3
-rw-r--r--tools/doxygen/Doxyfile.c++10
-rw-r--r--tools/doxygen/Doxyfile.c++.internal13
-rw-r--r--tools/doxygen/Doxyfile.core1
-rw-r--r--tools/doxygen/Doxyfile.core.internal18
-rwxr-xr-xtools/gce/create_linux_kokoro_performance_worker_from_image.sh2
-rwxr-xr-xtools/gce/linux_kokoro_performance_worker_init.sh6
-rwxr-xr-xtools/gcp/utils/big_query_utils.py28
-rw-r--r--tools/internal_ci/README.md11
-rw-r--r--tools/internal_ci/helper_scripts/prepare_build_macos_rc37
-rwxr-xr-xtools/internal_ci/linux/grpc_asan_on_foundry.sh2
-rwxr-xr-xtools/internal_ci/linux/grpc_bazel_on_foundry_base.sh22
-rw-r--r--tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh4
-rw-r--r--tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh4
-rwxr-xr-xtools/internal_ci/linux/grpc_coverage.sh20
-rwxr-xr-xtools/internal_ci/linux/grpc_e2e_performance_singlevm.sh2
-rwxr-xr-xtools/internal_ci/linux/grpc_full_performance_master.sh2
-rw-r--r--tools/internal_ci/linux/grpc_msan_on_foundry.sh66
-rwxr-xr-xtools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh2
-rwxr-xr-xtools/internal_ci/linux/grpc_run_tests_matrix.sh1
-rw-r--r--tools/internal_ci/linux/grpc_tsan_on_foundry.sh2
-rw-r--r--tools/internal_ci/linux/grpc_ubsan_on_foundry.sh2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh4
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh4
-rw-r--r--[-rwxr-xr-x]tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh (renamed from tools/run_tests/helper_scripts/run_lcov.sh)19
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh2
-rw-r--r--tools/internal_ci/macos/grpc_basictests_dbg.cfg2
-rw-r--r--tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg31
-rw-r--r--tools/internal_ci/macos/grpc_basictests_objc_opt.cfg31
-rw-r--r--tools/internal_ci/macos/grpc_basictests_opt.cfg2
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg2
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg31
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg31
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg2
-rw-r--r--tools/interop_matrix/client_matrix.py3
-rw-r--r--tools/remote_build/README.md7
-rw-r--r--tools/remote_build/kokoro.bazelrc20
-rw-r--r--tools/remote_build/manual.bazelrc3
-rw-r--r--tools/remote_build/rbe_common.bazelrc46
-rw-r--r--tools/run_tests/artifacts/artifact_targets.py2
-rw-r--r--tools/run_tests/artifacts/build_artifact_python.bat4
-rwxr-xr-xtools/run_tests/artifacts/build_artifact_python.sh13
-rwxr-xr-xtools/run_tests/artifacts/build_package_python.sh14
-rwxr-xr-xtools/run_tests/dockerize/build_docker_and_run_tests.sh5
-rwxr-xr-xtools/run_tests/dockerize/build_interop_image.sh4
-rwxr-xr-xtools/run_tests/dockerize/docker_run_tests.sh12
-rw-r--r--tools/run_tests/generated/sources_and_headers.json135
-rw-r--r--tools/run_tests/generated/tests.json74
-rwxr-xr-xtools/run_tests/helper_scripts/build_python.sh34
-rwxr-xr-xtools/run_tests/performance/run_worker_csharp.sh2
-rwxr-xr-xtools/run_tests/python_utils/jobset.py6
-rwxr-xr-xtools/run_tests/python_utils/port_server.py16
-rw-r--r--tools/run_tests/python_utils/report_utils.py2
-rw-r--r--tools/run_tests/python_utils/start_port_server.py19
-rw-r--r--tools/run_tests/python_utils/upload_rbe_results.py2
-rwxr-xr-xtools/run_tests/python_utils/watch_dirs.py3
-rwxr-xr-xtools/run_tests/run_interop_tests.py64
-rwxr-xr-xtools/run_tests/run_tests.py51
-rwxr-xr-xtools/run_tests/run_tests_matrix.py7
-rwxr-xr-xtools/run_tests/sanity/check_bazel_workspace.py5
-rwxr-xr-xtools/run_tests/sanity/check_submodules.sh6
-rwxr-xr-xtools/run_tests/sanity/core_banned_functions.py4
852 files changed, 22514 insertions, 9490 deletions
diff --git a/.gitmodules b/.gitmodules
index afde4d34f3..06f1394df6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -42,3 +42,15 @@
path = third_party/libcxx
url = https://github.com/llvm-mirror/libcxx.git
branch = release_60
+[submodule "third_party/data-plane-api"]
+ path = third_party/data-plane-api
+ url = https://github.com/envoyproxy/data-plane-api.git
+[submodule "third_party/googleapis"]
+ path = third_party/googleapis
+ url = https://github.com/googleapis/googleapis.git
+[submodule "third_party/protoc-gen-validate"]
+ path = third_party/protoc-gen-validate
+ url = https://github.com/lyft/protoc-gen-validate.git
+[submodule "third_party/upb"]
+ path = third_party/upb
+ url = https://github.com/google/upb.git
diff --git a/AUTHORS b/AUTHORS
index 3e130afda2..0e8797391f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1,3 @@
+Dropbox, Inc.
Google Inc.
WeWork Companies Inc.
diff --git a/BUILD b/BUILD
index 65cd4715f1..9e3e594038 100644
--- a/BUILD
+++ b/BUILD
@@ -64,11 +64,11 @@ config_setting(
)
# This should be updated along with build.yaml
-g_stands_for = "gizmo"
+g_stands_for = "goose"
-core_version = "6.0.0-dev"
+core_version = "7.0.0-dev"
-version = "1.17.0-dev"
+version = "1.18.0-dev"
GPR_PUBLIC_HDRS = [
"include/grpc/support/alloc.h",
@@ -113,6 +113,7 @@ GRPC_SECURE_PUBLIC_HDRS = [
GRPCXX_SRCS = [
"src/cpp/client/channel_cc.cc",
"src/cpp/client/client_context.cc",
+ "src/cpp/client/client_interceptor.cc",
"src/cpp/client/create_channel.cc",
"src/cpp/client/create_channel_internal.cc",
"src/cpp/client/create_channel_posix.cc",
@@ -245,6 +246,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
+ "include/grpcpp/support/server_callback.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",
@@ -645,6 +647,7 @@ grpc_cc_library(
"debug_location",
"gpr_base",
"grpc_trace",
+ "ref_counted",
"ref_counted_ptr",
],
)
@@ -820,6 +823,7 @@ grpc_cc_library(
"src/core/lib/transport/timeout_encoding.cc",
"src/core/lib/transport/transport.cc",
"src/core/lib/transport/transport_op_string.cc",
+ "src/core/lib/uri/uri_parser.cc",
],
hdrs = [
"src/core/lib/avl/avl.h",
@@ -852,6 +856,7 @@ grpc_cc_library(
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
+ "src/core/lib/iomgr/dynamic_annotations.h",
"src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
@@ -954,6 +959,7 @@ grpc_cc_library(
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h",
+ "src/core/lib/uri/uri_parser.h",
],
external_deps = [
"zlib",
@@ -1044,16 +1050,15 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy.cc",
"src/core/ext/filters/client_channel/lb_policy_factory.cc",
"src/core/ext/filters/client_channel/lb_policy_registry.cc",
- "src/core/ext/filters/client_channel/method_params.cc",
"src/core/ext/filters/client_channel/parse_address.cc",
"src/core/ext/filters/client_channel/proxy_mapper.cc",
"src/core/ext/filters/client_channel/proxy_mapper_registry.cc",
"src/core/ext/filters/client_channel/resolver.cc",
"src/core/ext/filters/client_channel/resolver_registry.cc",
+ "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
"src/core/ext/filters/client_channel/retry_throttle.cc",
"src/core/ext/filters/client_channel/subchannel.cc",
"src/core/ext/filters/client_channel/subchannel_index.cc",
- "src/core/ext/filters/client_channel/uri_parser.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/backup_poller.h",
@@ -1067,17 +1072,16 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy.h",
"src/core/ext/filters/client_channel/lb_policy_factory.h",
"src/core/ext/filters/client_channel/lb_policy_registry.h",
- "src/core/ext/filters/client_channel/method_params.h",
"src/core/ext/filters/client_channel/parse_address.h",
"src/core/ext/filters/client_channel/proxy_mapper.h",
"src/core/ext/filters/client_channel/proxy_mapper_registry.h",
"src/core/ext/filters/client_channel/resolver.h",
"src/core/ext/filters/client_channel/resolver_factory.h",
"src/core/ext/filters/client_channel/resolver_registry.h",
+ "src/core/ext/filters/client_channel/resolver_result_parsing.h",
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_index.h",
- "src/core/ext/filters/client_channel/uri_parser.h",
],
language = "c++",
deps = [
@@ -1085,11 +1089,11 @@ grpc_cc_library(
"grpc_base",
"grpc_client_authority_filter",
"grpc_deadline_filter",
+ "health_proto",
"inlined_vector",
"orphanable",
"ref_counted",
"ref_counted_ptr",
- "health_proto",
],
)
@@ -1587,8 +1591,8 @@ grpc_cc_library(
"src/core/lib/security/security_connector/load_system_roots_linux.cc",
"src/core/lib/security/security_connector/local/local_security_connector.cc",
"src/core/lib/security/security_connector/security_connector.cc",
- "src/core/lib/security/security_connector/ssl_utils.cc",
"src/core/lib/security/security_connector/ssl/ssl_security_connector.cc",
+ "src/core/lib/security/security_connector/ssl_utils.cc",
"src/core/lib/security/transport/client_auth_filter.cc",
"src/core/lib/security/transport/secure_endpoint.cc",
"src/core/lib/security/transport/security_handshaker.cc",
@@ -1621,8 +1625,8 @@ grpc_cc_library(
"src/core/lib/security/security_connector/load_system_roots_linux.h",
"src/core/lib/security/security_connector/local/local_security_connector.h",
"src/core/lib/security/security_connector/security_connector.h",
- "src/core/lib/security/security_connector/ssl_utils.h",
"src/core/lib/security/security_connector/ssl/ssl_security_connector.h",
+ "src/core/lib/security/security_connector/ssl_utils.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_handshaker.h",
@@ -1648,6 +1652,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_encoder.cc",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.cc",
"src/core/ext/transport/chttp2/transport/chttp2_transport.cc",
+ "src/core/ext/transport/chttp2/transport/context_list.cc",
"src/core/ext/transport/chttp2/transport/flow_control.cc",
"src/core/ext/transport/chttp2/transport/frame_data.cc",
"src/core/ext/transport/chttp2/transport/frame_goaway.cc",
@@ -1671,6 +1676,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+ "src/core/ext/transport/chttp2/transport/context_list.h",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.h",
@@ -1957,10 +1963,9 @@ grpc_cc_library(
name = "tsi",
srcs = [
"src/core/tsi/alts/handshaker/alts_handshaker_client.cc",
- "src/core/tsi/alts/handshaker/alts_tsi_event.cc",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.cc",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc",
"src/core/tsi/alts/handshaker/alts_tsi_utils.cc",
- "src/core/tsi/alts_transport_security.cc",
"src/core/tsi/fake_transport_security.cc",
"src/core/tsi/local_transport_security.cc",
"src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc",
@@ -1971,11 +1976,10 @@ grpc_cc_library(
],
hdrs = [
"src/core/tsi/alts/handshaker/alts_handshaker_client.h",
- "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
"src/core/tsi/alts/handshaker/alts_tsi_utils.h",
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.h",
"src/core/tsi/ssl/session_cache/ssl_session.h",
@@ -2065,6 +2069,8 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
@@ -2077,14 +2083,18 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
"include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"include/grpcpp/impl/codegen/rpc_method.h",
"include/grpcpp/impl/codegen/rpc_service_method.h",
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
+ "include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
+ "include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 23ef8b3b64..6b02d778d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@
cmake_minimum_required(VERSION 2.8)
set(PACKAGE_NAME "grpc")
-set(PACKAGE_VERSION "1.17.0-dev")
+set(PACKAGE_VERSION "1.18.0-dev")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -584,9 +584,11 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx client_crash_test)
endif()
add_dependencies(buildtests_cxx client_crash_test_server)
+add_dependencies(buildtests_cxx client_interceptors_end2end_test)
add_dependencies(buildtests_cxx client_lb_end2end_test)
add_dependencies(buildtests_cxx codegen_test_full)
add_dependencies(buildtests_cxx codegen_test_minimal)
+add_dependencies(buildtests_cxx context_list_test)
add_dependencies(buildtests_cxx credentials_test)
add_dependencies(buildtests_cxx cxx_byte_buffer_test)
add_dependencies(buildtests_cxx cxx_slice_test)
@@ -664,6 +666,7 @@ add_dependencies(buildtests_cxx server_crash_test)
endif()
add_dependencies(buildtests_cxx server_crash_test_client)
add_dependencies(buildtests_cxx server_early_return_test)
+add_dependencies(buildtests_cxx server_interceptors_end2end_test)
add_dependencies(buildtests_cxx server_request_call_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx slice_hash_table_test)
@@ -1123,12 +1126,14 @@ add_library(grpc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
src/core/ext/transport/chttp2/transport/bin_decoder.cc
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -1195,7 +1200,7 @@ add_library(grpc
src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
src/core/tsi/alts/frame_protector/frame_handler.cc
src/core/tsi/alts/handshaker/alts_handshaker_client.cc
- src/core/tsi/alts/handshaker/alts_tsi_event.cc
+ src/core/tsi/alts/handshaker/alts_shared_resource.cc
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
@@ -1237,19 +1242,17 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/client_channel/health/health.pb.c
- src/core/tsi/alts_transport_security.cc
src/core/tsi/fake_transport_security.cc
src/core/tsi/local_transport_security.cc
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1544,6 +1547,7 @@ add_library(grpc_cronet
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc
src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
@@ -1553,6 +1557,7 @@ add_library(grpc_cronet
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -1589,16 +1594,15 @@ add_library(grpc_cronet
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/client_channel/health/health.pb.c
third_party/nanopb/pb_common.c
@@ -1647,7 +1651,7 @@ add_library(grpc_cronet
src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
src/core/tsi/alts/frame_protector/frame_handler.cc
src/core/tsi/alts/handshaker/alts_handshaker_client.cc
- src/core/tsi/alts/handshaker/alts_tsi_event.cc
+ src/core/tsi/alts/handshaker/alts_shared_resource.cc
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
@@ -1673,7 +1677,6 @@ add_library(grpc_cronet
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
src/core/ext/transport/chttp2/client/authority.cc
src/core/ext/transport/chttp2/client/chttp2_connector.cc
- src/core/tsi/alts_transport_security.cc
src/core/tsi/fake_transport_security.cc
src/core/tsi/local_transport_security.cc
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1947,6 +1950,7 @@ add_library(grpc_test_util
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/filters/client_channel/backup_poller.cc
src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -1961,16 +1965,15 @@ add_library(grpc_test_util
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/client_channel/health/health.pb.c
third_party/nanopb/pb_common.c
@@ -1980,6 +1983,7 @@ add_library(grpc_test_util
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -2266,6 +2270,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/filters/client_channel/backup_poller.cc
src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -2280,16 +2285,15 @@ add_library(grpc_test_util_unsecure
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/client_channel/health/health.pb.c
third_party/nanopb/pb_common.c
@@ -2299,6 +2303,7 @@ add_library(grpc_test_util_unsecure
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -2564,6 +2569,7 @@ add_library(grpc_unsecure
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -2571,6 +2577,7 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -2612,16 +2619,15 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/client_channel/health/health.pb.c
third_party/nanopb/pb_common.c
@@ -2860,6 +2866,7 @@ add_library(grpc++
src/cpp/server/secure_server_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_context.cc
+ src/cpp/client/client_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
@@ -3018,6 +3025,7 @@ foreach(_hdr
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
+ include/grpcpp/support/server_callback.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
include/grpcpp/support/status_code_enum.h
@@ -3112,6 +3120,8 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
@@ -3124,14 +3134,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
+ include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
+ include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -3224,6 +3238,7 @@ add_library(grpc++_cronet
src/cpp/server/insecure_server_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_context.cc
+ src/cpp/client/client_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
@@ -3267,6 +3282,7 @@ add_library(grpc++_cronet
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -3435,6 +3451,7 @@ add_library(grpc++_cronet
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
+ src/core/lib/uri/uri_parser.cc
src/core/lib/debug/trace.cc
src/core/ext/transport/chttp2/alpn/alpn.cc
src/core/ext/filters/http/client/http_client_filter.cc
@@ -3454,16 +3471,15 @@ add_library(grpc++_cronet
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -3593,6 +3609,7 @@ foreach(_hdr
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
+ include/grpcpp/support/server_callback.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
include/grpcpp/support/status_code_enum.h
@@ -3687,6 +3704,8 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
@@ -3699,14 +3718,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
+ include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
+ include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -3997,6 +4020,11 @@ add_library(grpc++_test_util
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+ test/cpp/end2end/test_health_check_service_impl.cc
test/cpp/end2end/test_service_impl.cc
test/cpp/util/byte_buffer_proto_helper.cc
test/cpp/util/channel_trace_proto_helper.cc
@@ -4033,6 +4061,9 @@ protobuf_generate_grpc_cpp(
protobuf_generate_grpc_cpp(
src/proto/grpc/testing/duplicate/echo_duplicate.proto
)
+protobuf_generate_grpc_cpp(
+ src/proto/grpc/testing/simple_messages.proto
+)
target_include_directories(grpc++_test_util
PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
@@ -4096,6 +4127,8 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
@@ -4108,14 +4141,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
+ include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
+ include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -4184,6 +4221,11 @@ add_library(grpc++_test_util_unsecure
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+ test/cpp/end2end/test_health_check_service_impl.cc
test/cpp/end2end/test_service_impl.cc
test/cpp/util/byte_buffer_proto_helper.cc
test/cpp/util/string_ref_helper.cc
@@ -4214,6 +4256,9 @@ protobuf_generate_grpc_cpp(
protobuf_generate_grpc_cpp(
src/proto/grpc/testing/duplicate/echo_duplicate.proto
)
+protobuf_generate_grpc_cpp(
+ src/proto/grpc/testing/simple_messages.proto
+)
target_include_directories(grpc++_test_util_unsecure
PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
@@ -4277,6 +4322,8 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
@@ -4289,14 +4336,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
+ include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
+ include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -4351,6 +4402,7 @@ add_library(grpc++_unsecure
src/cpp/server/insecure_server_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_context.cc
+ src/cpp/client/client_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
@@ -4508,6 +4560,7 @@ foreach(_hdr
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
+ include/grpcpp/support/server_callback.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
include/grpcpp/support/status_code_enum.h
@@ -4602,6 +4655,8 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
@@ -4614,14 +4669,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
+ include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
+ include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -5296,6 +5355,7 @@ add_library(qps
test/cpp/qps/qps_worker.cc
test/cpp/qps/report.cc
test/cpp/qps/server_async.cc
+ test/cpp/qps/server_callback.cc
test/cpp/qps/server_sync.cc
test/cpp/qps/usage_timer.cc
)
@@ -12405,6 +12465,48 @@ target_link_libraries(client_crash_test_server
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(client_interceptors_end2end_test
+ test/cpp/end2end/client_interceptors_end2end_test.cc
+ test/cpp/end2end/interceptors_util.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(client_interceptors_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(client_interceptors_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(client_lb_end2end_test
test/cpp/end2end/client_lb_end2end_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@@ -12622,6 +12724,45 @@ target_link_libraries(codegen_test_minimal
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(context_list_test
+ test/core/transport/chttp2/context_list_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(context_list_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(context_list_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(credentials_test
test/cpp/client/credentials_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@@ -12819,6 +12960,7 @@ if (gRPC_BUILD_TESTS)
add_executable(end2end_test
test/cpp/end2end/end2end_test.cc
+ test/cpp/end2end/interceptors_util.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
@@ -15275,6 +15417,48 @@ target_link_libraries(server_early_return_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(server_interceptors_end2end_test
+ test/cpp/end2end/interceptors_util.cc
+ test/cpp/end2end/server_interceptors_end2end_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(server_interceptors_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(server_interceptors_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(server_request_call_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e8582d9af5..1d14d5e0e3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -81,7 +81,7 @@ How to get your contributions merged smoothly and quickly.
copyright holder for the contribution (yourself, if you are signing the
individual CLA, or your company, for corporate CLAs) in the same PR as your
contribution. This needs to be done only once, for each company, or
- individual.
+ individual. Please keep this file in alphabetical order.
- Maintain **clean commit history** and use **meaningful commit messages**.
PRs with messy commit history are difficult to review and won't be merged.
diff --git a/Makefile b/Makefile
index d0a3f86383..ed4e219f8b 100644
--- a/Makefile
+++ b/Makefile
@@ -438,8 +438,8 @@ Q = @
endif
CORE_VERSION = 7.0.0-dev
-CPP_VERSION = 1.17.0-dev
-CSHARP_VERSION = 1.17.0-dev
+CPP_VERSION = 1.18.0-dev
+CSHARP_VERSION = 1.18.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -1164,9 +1164,11 @@ client_callback_end2end_test: $(BINDIR)/$(CONFIG)/client_callback_end2end_test
client_channel_stress_test: $(BINDIR)/$(CONFIG)/client_channel_stress_test
client_crash_test: $(BINDIR)/$(CONFIG)/client_crash_test
client_crash_test_server: $(BINDIR)/$(CONFIG)/client_crash_test_server
+client_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test
client_lb_end2end_test: $(BINDIR)/$(CONFIG)/client_lb_end2end_test
codegen_test_full: $(BINDIR)/$(CONFIG)/codegen_test_full
codegen_test_minimal: $(BINDIR)/$(CONFIG)/codegen_test_minimal
+context_list_test: $(BINDIR)/$(CONFIG)/context_list_test
credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
cxx_byte_buffer_test: $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test
cxx_slice_test: $(BINDIR)/$(CONFIG)/cxx_slice_test
@@ -1229,6 +1231,7 @@ server_context_test_spouse_test: $(BINDIR)/$(CONFIG)/server_context_test_spouse_
server_crash_test: $(BINDIR)/$(CONFIG)/server_crash_test
server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
+server_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
@@ -1667,9 +1670,11 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
+ $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/client_lb_end2end_test \
$(BINDIR)/$(CONFIG)/codegen_test_full \
$(BINDIR)/$(CONFIG)/codegen_test_minimal \
+ $(BINDIR)/$(CONFIG)/context_list_test \
$(BINDIR)/$(CONFIG)/credentials_test \
$(BINDIR)/$(CONFIG)/cxx_byte_buffer_test \
$(BINDIR)/$(CONFIG)/cxx_slice_test \
@@ -1725,6 +1730,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_crash_test \
$(BINDIR)/$(CONFIG)/server_crash_test_client \
$(BINDIR)/$(CONFIG)/server_early_return_test \
+ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@@ -1848,9 +1854,11 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
+ $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/client_lb_end2end_test \
$(BINDIR)/$(CONFIG)/codegen_test_full \
$(BINDIR)/$(CONFIG)/codegen_test_minimal \
+ $(BINDIR)/$(CONFIG)/context_list_test \
$(BINDIR)/$(CONFIG)/credentials_test \
$(BINDIR)/$(CONFIG)/cxx_byte_buffer_test \
$(BINDIR)/$(CONFIG)/cxx_slice_test \
@@ -1906,6 +1914,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_crash_test \
$(BINDIR)/$(CONFIG)/server_crash_test_client \
$(BINDIR)/$(CONFIG)/server_early_return_test \
+ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@@ -2306,12 +2315,16 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/client_channel_stress_test || ( echo test client_channel_stress_test failed ; exit 1 )
$(E) "[RUN] Testing client_crash_test"
$(Q) $(BINDIR)/$(CONFIG)/client_crash_test || ( echo test client_crash_test failed ; exit 1 )
+ $(E) "[RUN] Testing client_interceptors_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test || ( echo test client_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing client_lb_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/client_lb_end2end_test || ( echo test client_lb_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing codegen_test_full"
$(Q) $(BINDIR)/$(CONFIG)/codegen_test_full || ( echo test codegen_test_full failed ; exit 1 )
$(E) "[RUN] Testing codegen_test_minimal"
$(Q) $(BINDIR)/$(CONFIG)/codegen_test_minimal || ( echo test codegen_test_minimal failed ; exit 1 )
+ $(E) "[RUN] Testing context_list_test"
+ $(Q) $(BINDIR)/$(CONFIG)/context_list_test || ( echo test context_list_test failed ; exit 1 )
$(E) "[RUN] Testing credentials_test"
$(Q) $(BINDIR)/$(CONFIG)/credentials_test || ( echo test credentials_test failed ; exit 1 )
$(E) "[RUN] Testing cxx_byte_buffer_test"
@@ -2396,6 +2409,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/server_crash_test || ( echo test server_crash_test failed ; exit 1 )
$(E) "[RUN] Testing server_early_return_test"
$(Q) $(BINDIR)/$(CONFIG)/server_early_return_test || ( echo test server_early_return_test failed ; exit 1 )
+ $(E) "[RUN] Testing server_interceptors_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test || ( echo test server_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing server_request_call_test"
$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
$(E) "[RUN] Testing shutdown_test"
@@ -2728,12 +2743,12 @@ $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: protoc_dep_error
else
-$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
+$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
-$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=generate_mock_code=true:$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
@@ -2836,6 +2851,22 @@ $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc: src/pro
endif
ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc: protoc_dep_error
+else
+
+$(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc: src/proto/grpc/testing/simple_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[PROTOC] Generating protobuf CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc: src/proto/grpc/testing/simple_messages.proto $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
+endif
+
+ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error
else
@@ -3054,7 +3085,7 @@ install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-con
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3063,7 +3094,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_cronet.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3072,7 +3103,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_error_details.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3081,7 +3112,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_reflection.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3090,7 +3121,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_unsecure.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3099,7 +3130,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpcpp_channelz$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpcpp_channelz.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so
endif
ifneq ($(SYSTEM),MINGW32)
@@ -3116,7 +3147,7 @@ install-shared_csharp: shared_csharp strip-shared_csharp
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a $(prefix)/lib/libgrpc_csharp_ext.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.7
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.1
$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so
endif
ifneq ($(SYSTEM),MINGW32)
@@ -3590,12 +3621,14 @@ LIBGRPC_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc \
src/core/ext/transport/chttp2/transport/bin_decoder.cc \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -3662,7 +3695,7 @@ LIBGRPC_SRC = \
src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
src/core/tsi/alts/frame_protector/frame_handler.cc \
src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
- src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+ src/core/tsi/alts/handshaker/alts_shared_resource.cc \
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
@@ -3704,19 +3737,17 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
- src/core/tsi/alts_transport_security.cc \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -4005,6 +4036,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc \
src/core/ext/transport/cronet/transport/cronet_api_dummy.cc \
@@ -4014,6 +4046,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -4050,16 +4083,15 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
third_party/nanopb/pb_common.c \
@@ -4108,7 +4140,7 @@ LIBGRPC_CRONET_SRC = \
src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
src/core/tsi/alts/frame_protector/frame_handler.cc \
src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
- src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+ src/core/tsi/alts/handshaker/alts_shared_resource.cc \
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
@@ -4134,7 +4166,6 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
src/core/ext/transport/chttp2/client/authority.cc \
src/core/ext/transport/chttp2/client/chttp2_connector.cc \
- src/core/tsi/alts_transport_security.cc \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -4401,6 +4432,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/filters/client_channel/backup_poller.cc \
src/core/ext/filters/client_channel/channel_connectivity.cc \
@@ -4415,16 +4447,15 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
third_party/nanopb/pb_common.c \
@@ -4434,6 +4465,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -4706,6 +4738,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/filters/client_channel/backup_poller.cc \
src/core/ext/filters/client_channel/channel_connectivity.cc \
@@ -4720,16 +4753,15 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
third_party/nanopb/pb_common.c \
@@ -4739,6 +4771,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -4977,6 +5010,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \
@@ -4984,6 +5018,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -5025,16 +5060,15 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
third_party/nanopb/pb_common.c \
@@ -5238,6 +5272,7 @@ LIBGRPC++_SRC = \
src/cpp/server/secure_server_credentials.cc \
src/cpp/client/channel_cc.cc \
src/cpp/client/client_context.cc \
+ src/cpp/client/client_interceptor.cc \
src/cpp/client/create_channel.cc \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_posix.cc \
@@ -5361,6 +5396,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
+ include/grpcpp/support/server_callback.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
include/grpcpp/support/status_code_enum.h \
@@ -5455,6 +5491,8 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -5467,14 +5505,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+ include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+ include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -5612,6 +5654,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/server/insecure_server_credentials.cc \
src/cpp/client/channel_cc.cc \
src/cpp/client/client_context.cc \
+ src/cpp/client/client_interceptor.cc \
src/cpp/client/create_channel.cc \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_posix.cc \
@@ -5655,6 +5698,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -5823,6 +5867,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/transport/chttp2/alpn/alpn.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
@@ -5842,16 +5887,15 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \
@@ -5945,6 +5989,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
+ include/grpcpp/support/server_callback.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
include/grpcpp/support/status_code_enum.h \
@@ -6039,6 +6084,8 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -6051,14 +6098,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+ include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+ include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6387,6 +6438,8 @@ LIBGRPC++_TEST_UTIL_SRC = \
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \
+ $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc \
+ test/cpp/end2end/test_health_check_service_impl.cc \
test/cpp/end2end/test_service_impl.cc \
test/cpp/util/byte_buffer_proto_helper.cc \
test/cpp/util/channel_trace_proto_helper.cc \
@@ -6433,6 +6486,8 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -6445,14 +6500,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+ include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+ include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6533,14 +6592,15 @@ ifneq ($(NO_DEPS),true)
-include $(LIBGRPC++_TEST_UTIL_OBJS:.o=.dep)
endif
endif
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/channel_trace_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_health_check_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/channel_trace_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
LIBGRPC++_TEST_UTIL_UNSECURE_SRC = \
@@ -6548,6 +6608,8 @@ LIBGRPC++_TEST_UTIL_UNSECURE_SRC = \
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \
+ $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc \
+ test/cpp/end2end/test_health_check_service_impl.cc \
test/cpp/end2end/test_service_impl.cc \
test/cpp/util/byte_buffer_proto_helper.cc \
test/cpp/util/string_ref_helper.cc \
@@ -6591,6 +6653,8 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -6603,14 +6667,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+ include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+ include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6691,11 +6759,12 @@ ifneq ($(NO_DEPS),true)
-include $(LIBGRPC++_TEST_UTIL_UNSECURE_OBJS:.o=.dep)
endif
endif
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_health_check_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc
LIBGRPC++_UNSECURE_SRC = \
@@ -6704,6 +6773,7 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/server/insecure_server_credentials.cc \
src/cpp/client/channel_cc.cc \
src/cpp/client/client_context.cc \
+ src/cpp/client/client_interceptor.cc \
src/cpp/client/create_channel.cc \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_posix.cc \
@@ -6827,6 +6897,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
+ include/grpcpp/support/server_callback.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
include/grpcpp/support/status_code_enum.h \
@@ -6921,6 +6992,8 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -6933,14 +7006,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+ include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+ include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -7556,6 +7633,7 @@ LIBQPS_SRC = \
test/cpp/qps/qps_worker.cc \
test/cpp/qps/report.cc \
test/cpp/qps/server_async.cc \
+ test/cpp/qps/server_callback.cc \
test/cpp/qps/server_sync.cc \
test/cpp/qps/usage_timer.cc \
@@ -7613,6 +7691,7 @@ $(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_server_builder.o: $(GENDIR)/src/proto/grpc/
$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_callback.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/usage_timer.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
@@ -17279,6 +17358,52 @@ endif
endif
+CLIENT_INTERCEPTORS_END2END_TEST_SRC = \
+ test/cpp/end2end/client_interceptors_end2end_test.cc \
+ test/cpp/end2end/interceptors_util.cc \
+
+CLIENT_INTERCEPTORS_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_INTERCEPTORS_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: $(PROTOBUF_DEP) $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_interceptors_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_client_interceptors_end2end_test: $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CLIENT_LB_END2END_TEST_SRC = \
test/cpp/end2end/client_lb_end2end_test.cc \
@@ -17456,6 +17581,49 @@ $(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test_minimal.o: $(GENDIR)/src/proto
$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+CONTEXT_LIST_TEST_SRC = \
+ test/core/transport/chttp2/context_list_test.cc \
+
+CONTEXT_LIST_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CONTEXT_LIST_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/context_list_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/context_list_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/context_list_test: $(PROTOBUF_DEP) $(CONTEXT_LIST_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CONTEXT_LIST_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/context_list_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/transport/chttp2/context_list_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_context_list_test: $(CONTEXT_LIST_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CONTEXT_LIST_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CREDENTIALS_TEST_SRC = \
test/cpp/client/credentials_test.cc \
@@ -17673,6 +17841,7 @@ endif
END2END_TEST_SRC = \
test/cpp/end2end/end2end_test.cc \
+ test/cpp/end2end/interceptors_util.cc \
END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(END2END_TEST_SRC))))
ifeq ($(NO_SECURE),true)
@@ -17705,6 +17874,8 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
deps_end2end_test: $(END2END_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
@@ -20064,6 +20235,52 @@ endif
endif
+SERVER_INTERCEPTORS_END2END_TEST_SRC = \
+ test/cpp/end2end/interceptors_util.cc \
+ test/cpp/end2end/server_interceptors_end2end_test.cc \
+
+SERVER_INTERCEPTORS_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_INTERCEPTORS_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: $(PROTOBUF_DEP) $(SERVER_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(SERVER_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/server_interceptors_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_server_interceptors_end2end_test: $(SERVER_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(SERVER_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
SERVER_REQUEST_CALL_TEST_SRC = \
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
@@ -24882,7 +25099,7 @@ src/core/tsi/alts/frame_protector/frame_handler.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/alts_handshaker_client.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc: $(OPENSSL_DEP)
-src/core/tsi/alts/handshaker/alts_tsi_event.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_shared_resource.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/alts_tsi_utils.cc: $(OPENSSL_DEP)
src/core/tsi/alts/handshaker/altscontext.pb.c: $(OPENSSL_DEP)
@@ -24894,7 +25111,6 @@ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_p
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc: $(OPENSSL_DEP)
src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc: $(OPENSSL_DEP)
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc: $(OPENSSL_DEP)
-src/core/tsi/alts_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/fake_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/local_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc: $(OPENSSL_DEP)
@@ -24930,6 +25146,7 @@ test/core/tsi/alts/crypt/gsec_test_util.cc: $(OPENSSL_DEP)
test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc: $(OPENSSL_DEP)
test/core/util/reconnect_server.cc: $(OPENSSL_DEP)
test/core/util/test_tcp_server.cc: $(OPENSSL_DEP)
+test/cpp/end2end/test_health_check_service_impl.cc: $(OPENSSL_DEP)
test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP)
test/cpp/interop/client.cc: $(OPENSSL_DEP)
test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
@@ -24949,6 +25166,7 @@ test/cpp/qps/qps_server_builder.cc: $(OPENSSL_DEP)
test/cpp/qps/qps_worker.cc: $(OPENSSL_DEP)
test/cpp/qps/report.cc: $(OPENSSL_DEP)
test/cpp/qps/server_async.cc: $(OPENSSL_DEP)
+test/cpp/qps/server_callback.cc: $(OPENSSL_DEP)
test/cpp/qps/server_sync.cc: $(OPENSSL_DEP)
test/cpp/qps/usage_timer.cc: $(OPENSSL_DEP)
test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index b30a1fbf90..544fefbc48 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -9,6 +9,7 @@ graft third_party/boringssl
graft third_party/cares
graft third_party/nanopb
graft third_party/zlib
+include src/python/grpcio/_parallel_compile_patch.py
include src/python/grpcio/_spawn_patch.py
include src/python/grpcio/commands.py
include src/python/grpcio/grpc_version.py
@@ -19,3 +20,4 @@ include src/python/grpcio/README.rst
include requirements.txt
include etc/roots.pem
include Makefile
+include LICENSE
diff --git a/README.md b/README.md
index 1960f44137..b3a4c1f17d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
gRPC - An RPC library and framework
===================================
-gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. It enables client and server applications to communicate transparently, and makes it easier to build connected systems.
+gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. gRPC enables client and server applications to communicate transparently, and simplifies the building of connected systems.
<table>
<tr>
@@ -18,10 +18,10 @@ gRPC is a modern, open source, high-performance remote procedure call (RPC) fram
# To start using gRPC
-To maximize usability, gRPC supports the standard way of adding dependencies in your language of choice (if there is one).
-In most languages, the gRPC runtime comes in form of a package available in your language's package manager.
+To maximize usability, gRPC supports the standard method for adding dependencies to a user's chosen language (if there is one).
+In most languages, the gRPC runtime comes as a package available in a user's language package manager.
-For instructions on how to use the language-specific gRPC runtime in your project, please refer to these documents
+For instructions on how to use the language-specific gRPC runtime for a project, please refer to these documents
* [C++](src/cpp): follow the instructions under the `src/cpp` directory
* [C#](src/csharp): NuGet package `Grpc`
@@ -35,7 +35,7 @@ For instructions on how to use the language-specific gRPC runtime in your projec
* [Ruby](src/ruby): `gem install grpc`
* [WebJS](https://github.com/grpc/grpc-web): follow the grpc-web instructions
-You can find per-language quickstart guides and tutorials in [Documentation section on grpc.io website](https://grpc.io/docs/). The code examples are available in the [examples](examples) directory.
+Per-language quickstart guides and tutorials can be found in the [documentation section on the grpc.io website](https://grpc.io/docs/). Code examples are available in the [examples](examples) directory.
Precompiled bleeding-edge package builds of gRPC `master` branch's `HEAD` are uploaded daily to [packages.grpc.io](https://packages.grpc.io).
@@ -43,9 +43,9 @@ Precompiled bleeding-edge package builds of gRPC `master` branch's `HEAD` are up
Contributions are welcome!
-Please read [How to contribute](CONTRIBUTING.md) which will guide you through the entire workflow of how to build the source code, how to run the tests and how to contribute your changes to
+Please read [How to contribute](CONTRIBUTING.md) which will guide you through the entire workflow of how to build the source code, how to run the tests, and how to contribute changes to
the gRPC codebase.
-The document also contains info on how the contributing process works and contains best practices for creating contributions.
+The "How to contribute" document also contains info on how the contribution process works and contains best practices for creating contributions.
# Troubleshooting
@@ -53,7 +53,7 @@ Sometimes things go wrong. Please check out the [Troubleshooting guide](TROUBLES
# Performance
-See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for the performance numbers for the latest released version.
+See the [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for performance numbers of the latest released version.
# Concepts
@@ -61,9 +61,9 @@ See [gRPC Concepts](CONCEPTS.md)
# About This Repository
-This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core](src/core).
+This repository contains source code for gRPC libraries implemented in multiple languages written on top of a shared C core library [src/core](src/core).
-Libraries in different languages may be in different states of development. We are seeking contributions for all of these libraries.
+Libraries in different languages may be in various states of development. We are seeking contributions for all of these libraries:
| Language | Source |
|-------------------------|-------------------------------------|
diff --git a/WORKSPACE b/WORKSPACE
index a547c24cbe..81371bf418 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,45 +1,62 @@
-workspace(name="com_github_grpc_grpc")
+workspace(name = "com_github_grpc_grpc")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps")
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
grpc_deps()
+
grpc_test_only_deps()
-new_http_archive(
- name="cython",
- sha256="d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27",
- urls=[
+register_execution_platforms(
+ "//third_party/toolchains:rbe_ubuntu1604",
+ "//third_party/toolchains:rbe_ubuntu1604_large",
+)
+
+register_toolchains(
+ "//third_party/toolchains:cc-toolchain-clang-x86_64-default",
+)
+
+http_archive(
+ name = "cython",
+ build_file = "//third_party:cython.BUILD",
+ sha256 = "d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27",
+ strip_prefix = "cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c",
+ urls = [
"https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz",
],
- strip_prefix="cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c",
- build_file="//third_party:cython.BUILD",
)
load("//third_party/py:python_configure.bzl", "python_configure")
-python_configure(name="local_config_python")
+
+python_configure(name = "local_config_python")
git_repository(
- name="io_bazel_rules_python",
- remote="https://github.com/bazelbuild/rules_python.git",
- commit="8b5d0683a7d878b28fffe464779c8a53659fc645",
+ name = "io_bazel_rules_python",
+ commit = "8b5d0683a7d878b28fffe464779c8a53659fc645",
+ remote = "https://github.com/bazelbuild/rules_python.git",
)
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories", "pip_import")
pip_repositories()
+
pip_import(
- name="grpc_python_dependencies",
- requirements="//:requirements.bazel.txt",
+ name = "grpc_python_dependencies",
+ requirements = "//:requirements.bazel.txt",
)
load("@grpc_python_dependencies//:requirements.bzl", "pip_install")
+
pip_install()
# NOTE(https://github.com/pubref/rules_protobuf/pull/196): Switch to upstream repo after this gets merged.
git_repository(
- name="org_pubref_rules_protobuf",
- remote="https://github.com/ghostwriternr/rules_protobuf",
- tag="v0.8.2.1-alpha",
+ name = "org_pubref_rules_protobuf",
+ remote = "https://github.com/ghostwriternr/rules_protobuf",
+ tag = "v0.8.2.1-alpha",
)
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories")
+
py_proto_repositories()
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 159ebd5d1f..65fe5a10aa 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -131,7 +131,7 @@ def grpc_proto_library(
generate_mocks = generate_mocks,
)
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate", tags = []):
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate", tags = [], exec_compatible_with = []):
copts = []
if language.upper() == "C":
copts = if_not_windows(["-std=c99"])
@@ -145,6 +145,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
"linkopts": if_not_windows(["-pthread"]),
"size": size,
"timeout": timeout,
+ "exec_compatible_with": exec_compatible_with,
}
if uses_polling:
native.cc_test(testonly = True, tags = ["manual"], **args)
@@ -162,6 +163,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
"$(location %s)" % name,
] + args["args"],
tags = tags,
+ exec_compatible_with = exec_compatible_with,
)
else:
native.cc_test(**args)
diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl
index 03bed3593d..3eacd2b047 100644
--- a/bazel/grpc_deps.bzl
+++ b/bazel/grpc_deps.bzl
@@ -1,5 +1,8 @@
"""Load dependencies needed to compile and test the grpc library as a 3rd-party consumer."""
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
def grpc_deps():
"""Loads dependencies need to compile and test the grpc library."""
@@ -9,6 +12,11 @@ def grpc_deps():
)
native.bind(
+ name = "upblib",
+ actual = "@upb//:upb",
+ )
+
+ native.bind(
name = "absl-base",
actual = "@com_google_absl//absl/base",
)
@@ -99,14 +107,14 @@ def grpc_deps():
)
if "boringssl" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "boringssl",
# on the chromium-stable-with-bazel branch
- url = "https://boringssl.googlesource.com/boringssl/+archive/dcd3e6e6ecddf059adb48fca45bc7346a108bdd9.tar.gz",
+ url = "https://boringssl.googlesource.com/boringssl/+archive/afc30d43eef92979b05776ec0963c9cede5fb80f.tar.gz",
)
if "com_github_madler_zlib" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_madler_zlib",
build_file = "@com_github_grpc_grpc//third_party:zlib.BUILD",
strip_prefix = "zlib-cacf7f1d4e3d44d871b605da3b647f07d718623f",
@@ -114,14 +122,14 @@ def grpc_deps():
)
if "com_google_protobuf" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "com_google_protobuf",
strip_prefix = "protobuf-48cb18e5c419ddd23d9badcfe4e9df7bde1979b2",
url = "https://github.com/google/protobuf/archive/48cb18e5c419ddd23d9badcfe4e9df7bde1979b2.tar.gz",
)
if "com_github_nanopb_nanopb" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_nanopb_nanopb",
build_file = "@com_github_grpc_grpc//third_party:nanopb.BUILD",
strip_prefix = "nanopb-f8ac463766281625ad710900479130c7fcb4d63b",
@@ -129,7 +137,7 @@ def grpc_deps():
)
if "com_github_google_googletest" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_google_googletest",
build_file = "@com_github_grpc_grpc//third_party:gtest.BUILD",
strip_prefix = "googletest-ec44c6c1675c25b9827aacd08c02433cccde7780",
@@ -137,14 +145,14 @@ def grpc_deps():
)
if "com_github_gflags_gflags" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "com_github_gflags_gflags",
strip_prefix = "gflags-30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e",
url = "https://github.com/gflags/gflags/archive/30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e.tar.gz",
)
if "com_github_google_benchmark" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_google_benchmark",
build_file = "@com_github_grpc_grpc//third_party:benchmark.BUILD",
strip_prefix = "benchmark-9913418d323e64a0111ca0da81388260c2bbe1e9",
@@ -152,7 +160,7 @@ def grpc_deps():
)
if "com_github_cares_cares" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_cares_cares",
build_file = "@com_github_grpc_grpc//third_party:cares/cares.BUILD",
strip_prefix = "c-ares-3be1924221e1326df520f8498d704a5c4c8d0cce",
@@ -160,14 +168,14 @@ def grpc_deps():
)
if "com_google_absl" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "com_google_absl",
strip_prefix = "abseil-cpp-cd95e71df6eaf8f2a282b1da556c2cf1c9b09207",
url = "https://github.com/abseil/abseil-cpp/archive/cd95e71df6eaf8f2a282b1da556c2cf1c9b09207.tar.gz",
)
if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "com_github_bazelbuild_bazeltoolchains",
strip_prefix = "bazel-toolchains-280edaa6f93623074513d2b426068de42e62ea4d",
urls = [
@@ -178,12 +186,19 @@ def grpc_deps():
)
if "io_opencensus_cpp" not in native.existing_rules():
- native.http_archive(
+ http_archive(
name = "io_opencensus_cpp",
strip_prefix = "opencensus-cpp-fdf0f308b1631bb4a942e32ba5d22536a6170274",
url = "https://github.com/census-instrumentation/opencensus-cpp/archive/fdf0f308b1631bb4a942e32ba5d22536a6170274.tar.gz",
)
+ if "upb" not in native.existing_rules():
+ http_archive(
+ name = "upb",
+ strip_prefix = "upb-9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3",
+ url = "https://github.com/google/upb/archive/9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3.tar.gz",
+ )
+
# TODO: move some dependencies from "grpc_deps" here?
def grpc_test_only_deps():
@@ -200,7 +215,7 @@ def grpc_test_only_deps():
)
if "com_github_twisted_twisted" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_twisted_twisted",
strip_prefix = "twisted-twisted-17.5.0",
url = "https://github.com/twisted/twisted/archive/twisted-17.5.0.zip",
@@ -208,7 +223,7 @@ def grpc_test_only_deps():
)
if "com_github_yaml_pyyaml" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_yaml_pyyaml",
strip_prefix = "pyyaml-3.12",
url = "https://github.com/yaml/pyyaml/archive/3.12.zip",
@@ -216,7 +231,7 @@ def grpc_test_only_deps():
)
if "com_github_twisted_incremental" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_twisted_incremental",
strip_prefix = "incremental-incremental-17.5.0",
url = "https://github.com/twisted/incremental/archive/incremental-17.5.0.zip",
@@ -224,7 +239,7 @@ def grpc_test_only_deps():
)
if "com_github_zopefoundation_zope_interface" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_zopefoundation_zope_interface",
strip_prefix = "zope.interface-4.4.3",
url = "https://github.com/zopefoundation/zope.interface/archive/4.4.3.zip",
@@ -232,7 +247,7 @@ def grpc_test_only_deps():
)
if "com_github_twisted_constantly" not in native.existing_rules():
- native.new_http_archive(
+ http_archive(
name = "com_github_twisted_constantly",
strip_prefix = "constantly-15.1.0",
url = "https://github.com/twisted/constantly/archive/15.1.0.zip",
diff --git a/build.yaml b/build.yaml
index d8d51c1b94..af70be8459 100644
--- a/build.yaml
+++ b/build.yaml
@@ -13,8 +13,8 @@ settings:
'#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here
core_version: 7.0.0-dev
- g_stands_for: gizmo
- version: 1.17.0-dev
+ g_stands_for: goose
+ version: 1.18.0-dev
filegroups:
- name: alts_proto
headers:
@@ -36,7 +36,7 @@ filegroups:
- src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h
- src/core/tsi/alts/frame_protector/frame_handler.h
- src/core/tsi/alts/handshaker/alts_handshaker_client.h
- - src/core/tsi/alts/handshaker/alts_tsi_event.h
+ - src/core/tsi/alts/handshaker/alts_shared_resource.h
- src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
- src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
- src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h
@@ -56,7 +56,7 @@ filegroups:
- src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
- src/core/tsi/alts/frame_protector/frame_handler.cc
- src/core/tsi/alts/handshaker/alts_handshaker_client.cc
- - src/core/tsi/alts/handshaker/alts_tsi_event.cc
+ - src/core/tsi/alts/handshaker/alts_shared_resource.cc
- src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
- src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
- src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
@@ -382,6 +382,7 @@ filegroups:
- src/core/lib/transport/timeout_encoding.cc
- src/core/lib/transport/transport.cc
- src/core/lib/transport/transport_op_string.cc
+ - src/core/lib/uri/uri_parser.cc
deps:
- gpr
filegroups:
@@ -439,6 +440,7 @@ filegroups:
- src/core/lib/iomgr/call_combiner.h
- src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/combiner.h
+ - src/core/lib/iomgr/dynamic_annotations.h
- src/core/lib/iomgr/endpoint.h
- src/core/lib/iomgr/endpoint_pair.h
- src/core/lib/iomgr/error.h
@@ -538,6 +540,7 @@ filegroups:
- src/core/lib/transport/timeout_encoding.h
- src/core/lib/transport/transport.h
- src/core/lib/transport/transport_impl.h
+ - src/core/lib/uri/uri_parser.h
deps:
- gpr
uses:
@@ -578,17 +581,16 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy.h
- src/core/ext/filters/client_channel/lb_policy_factory.h
- src/core/ext/filters/client_channel/lb_policy_registry.h
- - src/core/ext/filters/client_channel/method_params.h
- src/core/ext/filters/client_channel/parse_address.h
- src/core/ext/filters/client_channel/proxy_mapper.h
- src/core/ext/filters/client_channel/proxy_mapper_registry.h
- src/core/ext/filters/client_channel/resolver.h
- src/core/ext/filters/client_channel/resolver_factory.h
- src/core/ext/filters/client_channel/resolver_registry.h
+ - src/core/ext/filters/client_channel/resolver_result_parsing.h
- src/core/ext/filters/client_channel/retry_throttle.h
- src/core/ext/filters/client_channel/subchannel.h
- src/core/ext/filters/client_channel/subchannel_index.h
- - src/core/ext/filters/client_channel/uri_parser.h
src:
- src/core/ext/filters/client_channel/backup_poller.cc
- src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -603,16 +605,15 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy.cc
- src/core/ext/filters/client_channel/lb_policy_factory.cc
- src/core/ext/filters/client_channel/lb_policy_registry.cc
- - src/core/ext/filters/client_channel/method_params.cc
- src/core/ext/filters/client_channel/parse_address.cc
- src/core/ext/filters/client_channel/proxy_mapper.cc
- src/core/ext/filters/client_channel/proxy_mapper_registry.cc
- src/core/ext/filters/client_channel/resolver.cc
- src/core/ext/filters/client_channel/resolver_registry.cc
+ - src/core/ext/filters/client_channel/resolver_result_parsing.cc
- src/core/ext/filters/client_channel/retry_throttle.cc
- src/core/ext/filters/client_channel/subchannel.cc
- src/core/ext/filters/client_channel/subchannel_index.cc
- - src/core/ext/filters/client_channel/uri_parser.cc
plugin: grpc_client_channel
uses:
- grpc_base
@@ -962,6 +963,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/bin_decoder.h
- src/core/ext/transport/chttp2/transport/bin_encoder.h
- src/core/ext/transport/chttp2/transport/chttp2_transport.h
+ - src/core/ext/transport/chttp2/transport/context_list.h
- src/core/ext/transport/chttp2/transport/flow_control.h
- src/core/ext/transport/chttp2/transport/frame.h
- src/core/ext/transport/chttp2/transport/frame_data.h
@@ -984,6 +986,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/bin_encoder.cc
- src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
- src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+ - src/core/ext/transport/chttp2/transport/context_list.cc
- src/core/ext/transport/chttp2/transport/flow_control.cc
- src/core/ext/transport/chttp2/transport/frame_data.cc
- src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -1146,7 +1149,6 @@ filegroups:
- grpc
- name: tsi
headers:
- - src/core/tsi/alts_transport_security.h
- src/core/tsi/fake_transport_security.h
- src/core/tsi/local_transport_security.h
- src/core/tsi/ssl/session_cache/ssl_session.h
@@ -1155,7 +1157,6 @@ filegroups:
- src/core/tsi/ssl_types.h
- src/core/tsi/transport_security_grpc.h
src:
- - src/core/tsi/alts_transport_security.cc
- src/core/tsi/fake_transport_security.cc
- src/core/tsi/local_transport_security.cc
- src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1165,7 +1166,6 @@ filegroups:
- src/core/tsi/transport_security_grpc.cc
deps:
- gpr
- plugin: grpc_tsi_alts
secure: true
uses:
- tsi_interface
@@ -1222,6 +1222,8 @@ filegroups:
- include/grpcpp/impl/codegen/byte_buffer.h
- include/grpcpp/impl/codegen/call.h
- include/grpcpp/impl/codegen/call_hook.h
+ - include/grpcpp/impl/codegen/call_op_set.h
+ - include/grpcpp/impl/codegen/call_op_set_interface.h
- include/grpcpp/impl/codegen/callback_common.h
- include/grpcpp/impl/codegen/channel_interface.h
- include/grpcpp/impl/codegen/client_callback.h
@@ -1234,14 +1236,18 @@ filegroups:
- include/grpcpp/impl/codegen/core_codegen_interface.h
- include/grpcpp/impl/codegen/create_auth_context.h
- include/grpcpp/impl/codegen/grpc_library.h
+ - include/grpcpp/impl/codegen/intercepted_channel.h
- include/grpcpp/impl/codegen/interceptor.h
+ - include/grpcpp/impl/codegen/interceptor_common.h
- include/grpcpp/impl/codegen/metadata_map.h
- include/grpcpp/impl/codegen/method_handler_impl.h
- include/grpcpp/impl/codegen/rpc_method.h
- include/grpcpp/impl/codegen/rpc_service_method.h
- include/grpcpp/impl/codegen/security/auth_context.h
- include/grpcpp/impl/codegen/serialization_traits.h
+ - include/grpcpp/impl/codegen/server_callback.h
- include/grpcpp/impl/codegen/server_context.h
+ - include/grpcpp/impl/codegen/server_interceptor.h
- include/grpcpp/impl/codegen/server_interface.h
- include/grpcpp/impl/codegen/service_type.h
- include/grpcpp/impl/codegen/slice.h
@@ -1358,6 +1364,7 @@ filegroups:
- include/grpcpp/support/config.h
- include/grpcpp/support/proto_buffer_reader.h
- include/grpcpp/support/proto_buffer_writer.h
+ - include/grpcpp/support/server_callback.h
- include/grpcpp/support/slice.h
- include/grpcpp/support/status.h
- include/grpcpp/support/status_code_enum.h
@@ -1375,6 +1382,7 @@ filegroups:
src:
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_context.cc
+ - src/cpp/client/client_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
@@ -1747,6 +1755,7 @@ libs:
build: private
language: c++
headers:
+ - test/cpp/end2end/test_health_check_service_impl.h
- test/cpp/end2end/test_service_impl.h
- test/cpp/util/byte_buffer_proto_helper.h
- test/cpp/util/channel_trace_proto_helper.h
@@ -1760,6 +1769,8 @@ libs:
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/echo.proto
- src/proto/grpc/testing/duplicate/echo_duplicate.proto
+ - src/proto/grpc/testing/simple_messages.proto
+ - test/cpp/end2end/test_health_check_service_impl.cc
- test/cpp/end2end/test_service_impl.cc
- test/cpp/util/byte_buffer_proto_helper.cc
- test/cpp/util/channel_trace_proto_helper.cc
@@ -1780,6 +1791,7 @@ libs:
build: private
language: c++
headers:
+ - test/cpp/end2end/test_health_check_service_impl.h
- test/cpp/end2end/test_service_impl.h
- test/cpp/util/byte_buffer_proto_helper.h
- test/cpp/util/string_ref_helper.h
@@ -1789,6 +1801,8 @@ libs:
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/echo.proto
- src/proto/grpc/testing/duplicate/echo_duplicate.proto
+ - src/proto/grpc/testing/simple_messages.proto
+ - test/cpp/end2end/test_health_check_service_impl.cc
- test/cpp/end2end/test_service_impl.cc
- test/cpp/util/byte_buffer_proto_helper.cc
- test/cpp/util/string_ref_helper.cc
@@ -2029,6 +2043,7 @@ libs:
- test/cpp/qps/qps_worker.cc
- test/cpp/qps/report.cc
- test/cpp/qps/server_async.cc
+ - test/cpp/qps/server_callback.cc
- test/cpp/qps/server_sync.cc
- test/cpp/qps/usage_timer.cc
deps:
@@ -4480,6 +4495,7 @@ targets:
- gpr
- name: client_channel_stress_test
gtest: false
+ cpu_cost: 10.0
build: test
language: c++
src:
@@ -4523,6 +4539,23 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: client_interceptors_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
+ src:
+ - test/cpp/end2end/client_interceptors_end2end_test.cc
+ - test/cpp/end2end/interceptors_util.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: client_lb_end2end_test
gtest: true
build: test
@@ -4578,6 +4611,18 @@ targets:
- grpc++_codegen_base
- grpc++_codegen_base_src
uses_polling: false
+- name: context_list_test
+ gtest: true
+ build: test
+ language: c++
+ src:
+ - test/core/transport/chttp2/context_list_test.cc
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr_test_util
+ - gpr
+ uses_polling: false
- name: credentials_test
gtest: true
build: test
@@ -4642,8 +4687,11 @@ targets:
cpu_cost: 0.5
build: test
language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
src:
- test/cpp/end2end/end2end_test.cc
+ - test/cpp/end2end/interceptors_util.cc
deps:
- grpc++_test_util
- grpc_test_util
@@ -5435,6 +5483,23 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: server_interceptors_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
+ src:
+ - test/cpp/end2end/interceptors_util.cc
+ - test/cpp/end2end/server_interceptors_end2end_test.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: server_request_call_test
gtest: true
build: test
diff --git a/cmake/cares.cmake b/cmake/cares.cmake
index 3d4a0cae76..4ea0d8725d 100644
--- a/cmake/cares.cmake
+++ b/cmake/cares.cmake
@@ -18,6 +18,10 @@ if("${gRPC_CARES_PROVIDER}" STREQUAL "module")
endif()
set(CARES_SHARED OFF CACHE BOOL "disable shared library")
set(CARES_STATIC ON CACHE BOOL "link cares statically")
+ if(gRPC_BACKWARDS_COMPATIBILITY_MODE)
+ # See https://github.com/grpc/grpc/issues/17255
+ set(HAVE_LIBNSL OFF CACHE BOOL "avoid cares dependency on libnsl")
+ endif()
add_subdirectory(third_party/cares/cares)
if(TARGET c-ares)
diff --git a/config.m4 b/config.m4
index cf6769796b..3db660acee 100644
--- a/config.m4
+++ b/config.m4
@@ -234,12 +234,14 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
+ src/core/lib/uri/uri_parser.cc \
src/core/lib/debug/trace.cc \
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc \
src/core/ext/transport/chttp2/transport/bin_decoder.cc \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
+ src/core/ext/transport/chttp2/transport/context_list.cc \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_goaway.cc \
@@ -306,7 +308,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
src/core/tsi/alts/frame_protector/frame_handler.cc \
src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
- src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+ src/core/tsi/alts/handshaker/alts_shared_resource.cc \
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
@@ -348,19 +350,17 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
- src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
+ src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
- src/core/ext/filters/client_channel/uri_parser.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/client_channel/health/health.pb.c \
- src/core/tsi/alts_transport_security.cc \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -665,7 +665,8 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/third_party/fiat/curve25519.c \
, $ext_shared, , -fvisibility=hidden \
-DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN \
- -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0)
+ -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0 \
+ -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1)
PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
@@ -733,6 +734,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/slice)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/surface)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/uri)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/plugin_registry)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/crypt)
diff --git a/config.w32 b/config.w32
index da1279ccbc..7f8b6eee5f 100644
--- a/config.w32
+++ b/config.w32
@@ -209,12 +209,14 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\transport\\timeout_encoding.cc " +
"src\\core\\lib\\transport\\transport.cc " +
"src\\core\\lib\\transport\\transport_op_string.cc " +
+ "src\\core\\lib\\uri\\uri_parser.cc " +
"src\\core\\lib\\debug\\trace.cc " +
"src\\core\\ext\\transport\\chttp2\\server\\secure\\server_secure_chttp2.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\bin_decoder.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\bin_encoder.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\chttp2_plugin.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\chttp2_transport.cc " +
+ "src\\core\\ext\\transport\\chttp2\\transport\\context_list.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\flow_control.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_data.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_goaway.cc " +
@@ -281,7 +283,7 @@ if (PHP_GRPC != "no") {
"src\\core\\tsi\\alts\\frame_protector\\alts_unseal_privacy_integrity_crypter.cc " +
"src\\core\\tsi\\alts\\frame_protector\\frame_handler.cc " +
"src\\core\\tsi\\alts\\handshaker\\alts_handshaker_client.cc " +
- "src\\core\\tsi\\alts\\handshaker\\alts_tsi_event.cc " +
+ "src\\core\\tsi\\alts\\handshaker\\alts_shared_resource.cc " +
"src\\core\\tsi\\alts\\handshaker\\alts_tsi_handshaker.cc " +
"src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_integrity_only_record_protocol.cc " +
"src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_privacy_integrity_record_protocol.cc " +
@@ -323,19 +325,17 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " +
- "src\\core\\ext\\filters\\client_channel\\method_params.cc " +
"src\\core\\ext\\filters\\client_channel\\parse_address.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
+ "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
"src\\core\\ext\\filters\\client_channel\\subchannel.cc " +
"src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " +
- "src\\core\\ext\\filters\\client_channel\\uri_parser.cc " +
"src\\core\\ext\\filters\\deadline\\deadline_filter.cc " +
"src\\core\\ext\\filters\\client_channel\\health\\health.pb.c " +
- "src\\core\\tsi\\alts_transport_security.cc " +
"src\\core\\tsi\\fake_transport_security.cc " +
"src\\core\\tsi\\local_transport_security.cc " +
"src\\core\\tsi\\ssl\\session_cache\\ssl_session_boringssl.cc " +
@@ -749,6 +749,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\slice");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\surface");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\transport");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\uri");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\plugin_registry");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts");
diff --git a/doc/connectivity-semantics-and-api.md b/doc/connectivity-semantics-and-api.md
index dc30fe5348..44fdf050c6 100644
--- a/doc/connectivity-semantics-and-api.md
+++ b/doc/connectivity-semantics-and-api.md
@@ -23,9 +23,10 @@ make progress on one of the steps involved in name resolution, TCP connection
establishment or TLS handshake. This may be used as the initial state for channels upon
creation.
-READY: The channel has successfully established a connection all the way
-through TLS handshake (or equivalent) and all subsequent attempt to communicate
-have succeeded (or are pending without any known failure ).
+READY: The channel has successfully established a connection all the way through
+TLS handshake (or equivalent) and protocol-level (HTTP/2, etc) handshaking, and
+all subsequent attempt to communicate have succeeded (or are pending without any
+known failure).
TRANSIENT_FAILURE: There has been some transient failure (such as a TCP 3-way
handshake timing out or a socket error). Channels in this state will eventually
@@ -52,8 +53,8 @@ immediately. Pending RPCs may continue running till the application cancels them
Channels may enter this state either because the application explicitly requested
a shutdown or if a non-recoverable error has happened during attempts to connect
communicate . (As of 6/12/2015, there are no known errors (while connecting or
-communicating) that are classified as non-recoverable)
-Channels that enter this state never leave this state.
+communicating) that are classified as non-recoverable.) Channels that enter this
+state never leave this state.
The following table lists the legal transitions from one state to another and
corresponding reasons. Empty cells denote disallowed transitions.
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index 1eb850e976..d1172e62f4 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -140,3 +140,13 @@ some configuration as environment variables that can be set.
* grpc_cfstream
set to 1 to turn on CFStream experiment. With this experiment gRPC uses CFStream API to make TCP
connections. The option is only available on iOS platform and when macro GRPC_CFSTREAM is defined.
+
+* GRPC_ARENA_INIT_STRATEGY
+ Selects the initialization strategy for blocks allocated in the arena. Valid
+ values are:
+ - no_init (default): Do not inialize the arena block.
+ - zero_init: Initialize the arena blocks with 0.
+ - non_zero_init: Initialize the arena blocks with a non-zero value.
+
+ NOTE: This environment variable is experimental and will be removed. Thus, it
+ should not be relied upon.
diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md
index a5a8efb21c..1e49b4d3f1 100644
--- a/doc/g_stands_for.md
+++ b/doc/g_stands_for.md
@@ -16,4 +16,5 @@
- 1.14 'g' stands for ['gladiolus'](https://github.com/grpc/grpc/tree/v1.14.x)
- 1.15 'g' stands for ['glider'](https://github.com/grpc/grpc/tree/v1.15.x)
- 1.16 'g' stands for ['gao'](https://github.com/grpc/grpc/tree/v1.16.x)
-- 1.17 'g' stands for ['gizmo'](https://github.com/grpc/grpc/tree/master)
+- 1.17 'g' stands for ['gizmo'](https://github.com/grpc/grpc/tree/v1.17.x)
+- 1.18 'g' stands for ['goose'](https://github.com/grpc/grpc/tree/master)
diff --git a/doc/grpc_release_schedule.md b/doc/grpc_release_schedule.md
new file mode 100644
index 0000000000..bacd375859
--- /dev/null
+++ b/doc/grpc_release_schedule.md
@@ -0,0 +1,22 @@
+# gRPC Release Schedule
+
+Below is the release schedule for gRPC [Java](https://github.com/grpc/grpc-java/releases), [Go](https://github.com/grpc/grpc-go/releases) and [Core](https://github.com/grpc/grpc/releases) and its dependent languages C++, C#, Objective-C, PHP, Python and Ruby.
+
+Releases are scheduled every six weeks on Tuesdays on a best effort basis. In some unavoidable situations a release may be delayed or a language may skip a release altogether and do the next release to catch up with other languages. See the past releases in the links above. A six-week cycle gives us a good balance between delivering new features/fixes quickly and keeping the release overhead low.
+
+Releases are cut from release branches. For Core and Java repos, the release branch is cut two weeks before the scheduled release date. For Go, the branch is cut just before the release. An RC (release candidate) is published for Core and its dependent languages just after the branch cut. This RC is later promoted to release version if no further changes are made to the release branch. We do our best to keep head of master branch stable at all times regardless of release schedule. Daily build packages from master branch for C#, PHP, Python, Ruby and Protoc plugins are published on [packages.grpc.io](https://packages.grpc.io/). If you depend on gRPC in production we recommend to set up your CI system to test the RCs and, if possible, the daily builds.
+
+Names of gRPC releases are [here](https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md).
+
+Release |Scheduled Branch Cut|Scheduled Release Date
+--------|--------------------|-------------
+v1.17.0 |Nov 19, 2018 |Dec 4, 2018
+v1.18.0 |Jan 2, 2019 |Jan 15, 2019
+v1.19.0 |Feb 12, 2019 |Feb 26, 2019
+v1.20.0 |Mar 26, 2019 |Apr 9, 2019
+v1.21.0 |May 7, 2019 |May 21, 2019
+v1.22.0 |Jun 18, 2019 |Jul 2, 2019
+v1.23.0 |Jul 30, 2019 |Aug 13, 2019
+v1.24.0 |Sept 10, 2019 |Sept 24, 2019
+v1.25.0 |Oct 22, 2019 |Nov 5, 2019
+v1.26.0 |Dec 3, 2019 |Dec 17, 2019
diff --git a/doc/naming.md b/doc/naming.md
index 581c550567..5e54ca67b3 100644
--- a/doc/naming.md
+++ b/doc/naming.md
@@ -51,7 +51,9 @@ but may not be supported in other languages:
- `ipv6:address[:port][,address[:port],...]` -- IPv6 addresses
- Can specify multiple comma-delimited addresses of the form `address[:port]`:
- - `address` is the IPv6 address to use.
+ - `address` is the IPv6 address to use. To use with a `port` the `address`
+ must enclosed in literal square brakets (`[` and `]`). Example:
+ `ipv6:[2607:f8b0:400e:c00::ef]:443` or `ipv6:[::]:1234`
- `port` is the port to use. If not specified, 443 is used.
In the future, additional schemes such as `etcd` could be added.
diff --git a/doc/python/sphinx/conf.py b/doc/python/sphinx/conf.py
new file mode 100644
index 0000000000..307c3bdaf6
--- /dev/null
+++ b/doc/python/sphinx/conf.py
@@ -0,0 +1,105 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -- Path setup --------------------------------------------------------------
+
+import os
+import sys
+PYTHON_FOLDER = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ '..', '..', '..', 'src', 'python')
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_channelz'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_health_checking'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_reflection'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_testing'))
+
+# -- Project information -----------------------------------------------------
+
+project = 'gRPC Python'
+copyright = '2018, The gRPC Authors'
+author = 'The gRPC Authors'
+
+# Import generated grpc_version after the path been modified
+import grpc_version
+version = ".".join(grpc_version.VERSION.split(".")[:3])
+release = grpc_version.VERSION
+
+# -- General configuration ---------------------------------------------------
+
+templates_path = ['_templates']
+source_suffix = ['.rst', '.md']
+master_doc = 'index'
+language = 'en'
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+pygments_style = None
+
+# --- Extensions Configuration -----------------------------------------------
+
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.napoleon',
+ 'sphinx.ext.coverage',
+]
+
+napoleon_google_docstring = True
+napoleon_numpy_docstring = True
+napoleon_include_special_with_doc = True
+
+autodoc_default_options = {
+ 'members': None,
+}
+
+autodoc_mock_imports = [
+ 'grpc._cython',
+ 'grpc_channelz.v1.channelz_pb2',
+ 'grpc_channelz.v1.channelz_pb2_grpc',
+ 'grpc_health.v1.health_pb2',
+ 'grpc_health.v1.health_pb2_grpc',
+ 'grpc_reflection.v1alpha.reflection_pb2',
+ 'grpc_reflection.v1alpha.reflection_pb2_grpc',
+]
+
+# -- HTML Configuration -------------------------------------------------
+
+html_theme = 'alabaster'
+html_theme_options = {
+ 'fixed_sidebar': True,
+ 'page_width': '1140px',
+ 'show_related': True,
+ 'analytics_id': 'UA-60127042-1',
+ 'description': grpc_version.VERSION,
+ 'show_powered_by': False,
+}
+
+# -- Options for manual page output ------------------------------------------
+
+man_pages = [(master_doc, 'grpcio', 'grpcio Documentation', [author], 1)]
+
+# -- Options for Texinfo output ----------------------------------------------
+
+texinfo_documents = [
+ (master_doc, 'grpcio', 'grpcio Documentation', author, 'grpcio',
+ 'One line description of project.', 'Miscellaneous'),
+]
+
+# -- Options for Epub output -------------------------------------------------
+
+epub_title = project
+epub_exclude_files = ['search.html']
+
+# -- Options for todo extension ----------------------------------------------
+
+todo_include_todos = True
diff --git a/doc/python/sphinx/glossary.rst b/doc/python/sphinx/glossary.rst
new file mode 100644
index 0000000000..dee5d16143
--- /dev/null
+++ b/doc/python/sphinx/glossary.rst
@@ -0,0 +1,16 @@
+Glossary
+================
+
+.. glossary::
+
+ metadatum
+ A key-value pair included in the HTTP header. It is a
+ 2-tuple where the first entry is the key and the
+ second is the value, i.e. (key, value). The metadata key is an ASCII str,
+ and must be a valid HTTP header name. The metadata value can be
+ either a valid HTTP ASCII str, or bytes. If bytes are provided,
+ the key must end with '-bin', i.e.
+ ``('binary-metadata-bin', b'\\x00\\xFF')``
+
+ metadata
+ A sequence of metadatum.
diff --git a/doc/python/sphinx/grpc.rst b/doc/python/sphinx/grpc.rst
new file mode 100644
index 0000000000..bd2df9596b
--- /dev/null
+++ b/doc/python/sphinx/grpc.rst
@@ -0,0 +1,169 @@
+gRPC
+=============
+
+.. module:: grpc
+
+Tutorial
+--------
+
+If you want to see gRPC in action first, visit the `Python Quickstart <https://grpc.io/docs/quickstart/python.html>`_.
+Or, if you would like dive in with more extensive usage of gRPC Python, check `gRPC Basics - Python <https://grpc.io/docs/tutorials/basic/python.html>`_ out.
+
+
+Example
+-------
+
+Go to `gRPC Python Examples <https://github.com/grpc/grpc/tree/master/examples/python>`_
+
+
+Module Contents
+---------------
+
+Create Client
+^^^^^^^^^^^^^
+
+.. autofunction:: insecure_channel
+.. autofunction:: secure_channel
+.. autofunction:: intercept_channel
+
+
+Create Client Credentials
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: ssl_channel_credentials
+.. autofunction:: metadata_call_credentials
+.. autofunction:: access_token_call_credentials
+.. autofunction:: composite_call_credentials
+.. autofunction:: composite_channel_credentials
+
+
+Create Server
+^^^^^^^^^^^^^
+
+.. autofunction:: server
+
+
+Create Server Credentials
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: ssl_server_credentials
+.. autofunction:: ssl_server_certificate_configuration
+.. autofunction:: dynamic_ssl_server_credentials
+
+
+RPC Method Handlers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: unary_unary_rpc_method_handler
+.. autofunction:: unary_stream_rpc_method_handler
+.. autofunction:: stream_unary_rpc_method_handler
+.. autofunction:: stream_stream_rpc_method_handler
+.. autofunction:: method_handlers_generic_handler
+
+
+Channel Ready Future
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: channel_ready_future
+
+
+Channel Connectivity
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ChannelConnectivity
+
+
+gRPC Status Code
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: StatusCode
+
+
+Channel Object
+^^^^^^^^^^^^^^
+
+.. autoclass:: Channel
+
+
+Server Object
+^^^^^^^^^^^^^
+
+.. autoclass:: Server
+
+
+Authentication & Authorization Objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ChannelCredentials
+.. autoclass:: CallCredentials
+.. autoclass:: AuthMetadataContext
+.. autoclass:: AuthMetadataPluginCallback
+.. autoclass:: AuthMetadataPlugin
+.. autoclass:: ServerCredentials
+.. autoclass:: ServerCertificateConfiguration
+
+
+gRPC Exceptions
+^^^^^^^^^^^^^^^
+
+.. autoexception:: RpcError
+
+
+Shared Context
+^^^^^^^^^^^^^^
+
+.. autoclass:: RpcContext
+
+
+Client-Side Context
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: Call
+
+
+Client-Side Interceptor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ClientCallDetails
+.. autoclass:: UnaryUnaryClientInterceptor
+.. autoclass:: UnaryStreamClientInterceptor
+.. autoclass:: StreamUnaryClientInterceptor
+.. autoclass:: StreamStreamClientInterceptor
+
+
+Service-Side Context
+^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ServicerContext
+
+
+Service-Side Handler
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: RpcMethodHandler
+.. autoclass:: HandlerCallDetails
+.. autoclass:: GenericRpcHandler
+.. autoclass:: ServiceRpcHandler
+
+
+Service-Side Interceptor
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ServerInterceptor
+
+
+Multi-Callable Interfaces
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: UnaryUnaryMultiCallable
+.. autoclass:: UnaryStreamMultiCallable
+.. autoclass:: StreamUnaryMultiCallable
+.. autoclass:: StreamStreamMultiCallable
+
+
+Future Interfaces
+^^^^^^^^^^^^^^^^^
+
+.. autoexception:: FutureTimeoutError
+.. autoexception:: FutureCancelledError
+.. autoclass:: Future
diff --git a/doc/python/sphinx/grpc_channelz.rst b/doc/python/sphinx/grpc_channelz.rst
new file mode 100644
index 0000000000..f65793a071
--- /dev/null
+++ b/doc/python/sphinx/grpc_channelz.rst
@@ -0,0 +1,12 @@
+gRPC Channelz
+====================
+
+What is gRPC Channelz?
+---------------------------------------------
+
+Design Document `gRPC Channelz <https://github.com/grpc/proposal/blob/master/A14-channelz.md>`_
+
+Module Contents
+---------------
+
+.. automodule:: grpc_channelz.v1.channelz
diff --git a/doc/python/sphinx/grpc_health_checking.rst b/doc/python/sphinx/grpc_health_checking.rst
new file mode 100644
index 0000000000..b344e34ac9
--- /dev/null
+++ b/doc/python/sphinx/grpc_health_checking.rst
@@ -0,0 +1,7 @@
+gRPC Health Checking
+====================
+
+Module Contents
+---------------
+
+.. autoclass:: grpc_health.v1.health.HealthServicer
diff --git a/doc/python/sphinx/grpc_reflection.rst b/doc/python/sphinx/grpc_reflection.rst
new file mode 100644
index 0000000000..043f2edb96
--- /dev/null
+++ b/doc/python/sphinx/grpc_reflection.rst
@@ -0,0 +1,19 @@
+gRPC Reflection
+====================
+
+What is gRPC reflection?
+---------------------------------------------
+
+Check this out `gRPC Python Server Reflection <https://github.com/grpc/grpc/blob/master/doc/python/server_reflection.md>`_
+
+
+Example
+-------
+
+Refer to the GitHub `reflection example <https://github.com/grpc/grpc/blob/master/examples/python/helloworld/greeter_server_with_reflection.py>`_
+
+
+Module Contents
+---------------
+
+.. automodule:: grpc_reflection.v1alpha.reflection
diff --git a/doc/python/sphinx/grpc_testing.rst b/doc/python/sphinx/grpc_testing.rst
new file mode 100644
index 0000000000..adfeb8b384
--- /dev/null
+++ b/doc/python/sphinx/grpc_testing.rst
@@ -0,0 +1,7 @@
+gRPC Testing
+====================
+
+Module Contents
+---------------
+
+.. automodule:: grpc_testing
diff --git a/doc/python/sphinx/index.rst b/doc/python/sphinx/index.rst
new file mode 100644
index 0000000000..2f8a47a074
--- /dev/null
+++ b/doc/python/sphinx/index.rst
@@ -0,0 +1,25 @@
+Welcome to gRPC Python's documentation!
+=======================================
+
+Version: |version| Release: |release|
+
+API Reference
+=============
+
+.. toctree::
+ :caption: Contents:
+
+ grpc
+ grpc_channelz
+ grpc_health_checking
+ grpc_reflection
+ grpc_testing
+ glossary
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/examples/csharp/.gitignore b/examples/csharp/.gitignore
index 585000ea2d..11f758f5c8 100644
--- a/examples/csharp/.gitignore
+++ b/examples/csharp/.gitignore
@@ -1,5 +1,7 @@
+.vs/
bin/
obj/
packages/
*.suo
+*.user
*.userprefs
diff --git a/examples/csharp/Helloworld/Greeter.sln b/examples/csharp/Helloworld/Greeter.sln
index ca50470e66..a5ba98d0be 100644
--- a/examples/csharp/Helloworld/Greeter.sln
+++ b/examples/csharp/Helloworld/Greeter.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
diff --git a/examples/csharp/Helloworld/Greeter/Greeter.csproj b/examples/csharp/Helloworld/Greeter/Greeter.csproj
index eba262565d..7989f79541 100644
--- a/examples/csharp/Helloworld/Greeter/Greeter.csproj
+++ b/examples/csharp/Helloworld/Greeter/Greeter.csproj
@@ -1,18 +1,17 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>Greeter</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>Greeter</AssemblyName>
- <PackageId>Greeter</PackageId>
+ <TargetFramework>netstandard1.5</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
- <PackageReference Include="Google.Protobuf.Tools" Version="3.6.1" />
- <PackageReference Include="Grpc" Version="1.14.1" />
- <PackageReference Include="Grpc.Tools" Version="1.14.1" />
+ <PackageReference Include="Grpc" Version="1.17.0" />
+ <PackageReference Include="Grpc.Tools" Version="1.17.0" PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Protobuf Include="../../../protos/helloworld.proto" Link="helloworld.proto" />
</ItemGroup>
</Project>
diff --git a/examples/csharp/Helloworld/Greeter/Helloworld.cs b/examples/csharp/Helloworld/Greeter/Helloworld.cs
deleted file mode 100644
index e008ec27e5..0000000000
--- a/examples/csharp/Helloworld/Greeter/Helloworld.cs
+++ /dev/null
@@ -1,312 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: helloworld.proto
-// </auto-generated>
-#pragma warning disable 1591, 0612, 3021
-#region Designer generated code
-
-using pb = global::Google.Protobuf;
-using pbc = global::Google.Protobuf.Collections;
-using pbr = global::Google.Protobuf.Reflection;
-using scg = global::System.Collections.Generic;
-namespace Helloworld {
-
- /// <summary>Holder for reflection information generated from helloworld.proto</summary>
- public static partial class HelloworldReflection {
-
- #region Descriptor
- /// <summary>File descriptor for helloworld.proto</summary>
- public static pbr::FileDescriptor Descriptor {
- get { return descriptor; }
- }
- private static pbr::FileDescriptor descriptor;
-
- static HelloworldReflection() {
- byte[] descriptorData = global::System.Convert.FromBase64String(
- string.Concat(
- "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz",
- "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo",
- "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl",
- "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4",
- "YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw",
- "cm90bzM="));
- descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
- new pbr::FileDescriptor[] { },
- new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
- new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null)
- }));
- }
- #endregion
-
- }
- #region Messages
- /// <summary>
- /// The request message containing the user's name.
- /// </summary>
- public sealed partial class HelloRequest : pb::IMessage<HelloRequest> {
- private static readonly pb::MessageParser<HelloRequest> _parser = new pb::MessageParser<HelloRequest>(() => new HelloRequest());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<HelloRequest> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest(HelloRequest other) : this() {
- name_ = other.name_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest Clone() {
- return new HelloRequest(this);
- }
-
- /// <summary>Field number for the "name" field.</summary>
- public const int NameFieldNumber = 1;
- private string name_ = "";
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Name {
- get { return name_; }
- set {
- name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as HelloRequest);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(HelloRequest other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Name != other.Name) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Name.Length != 0) hash ^= Name.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Name.Length != 0) {
- output.WriteRawTag(10);
- output.WriteString(Name);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Name.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(HelloRequest other) {
- if (other == null) {
- return;
- }
- if (other.Name.Length != 0) {
- Name = other.Name;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- Name = input.ReadString();
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// The response message containing the greetings
- /// </summary>
- public sealed partial class HelloReply : pb::IMessage<HelloReply> {
- private static readonly pb::MessageParser<HelloReply> _parser = new pb::MessageParser<HelloReply>(() => new HelloReply());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<HelloReply> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply(HelloReply other) : this() {
- message_ = other.message_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply Clone() {
- return new HelloReply(this);
- }
-
- /// <summary>Field number for the "message" field.</summary>
- public const int MessageFieldNumber = 1;
- private string message_ = "";
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Message {
- get { return message_; }
- set {
- message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as HelloReply);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(HelloReply other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Message != other.Message) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Message.Length != 0) hash ^= Message.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Message.Length != 0) {
- output.WriteRawTag(10);
- output.WriteString(Message);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Message.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(HelloReply other) {
- if (other == null) {
- return;
- }
- if (other.Message.Length != 0) {
- Message = other.Message;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- Message = input.ReadString();
- break;
- }
- }
- }
- }
-
- }
-
- #endregion
-
-}
-
-#endregion Designer generated code
diff --git a/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs b/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs
deleted file mode 100644
index d6b959adc6..0000000000
--- a/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: helloworld.proto
-// </auto-generated>
-// Original file comments:
-// Copyright 2015 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#pragma warning disable 0414, 1591
-#region Designer generated code
-
-using grpc = global::Grpc.Core;
-
-namespace Helloworld {
- /// <summary>
- /// The greeting service definition.
- /// </summary>
- public static partial class Greeter
- {
- static readonly string __ServiceName = "helloworld.Greeter";
-
- static readonly grpc::Marshaller<global::Helloworld.HelloRequest> __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Helloworld.HelloReply> __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom);
-
- static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
- grpc::MethodType.Unary,
- __ServiceName,
- "SayHello",
- __Marshaller_helloworld_HelloRequest,
- __Marshaller_helloworld_HelloReply);
-
- /// <summary>Service descriptor</summary>
- public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
- {
- get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; }
- }
-
- /// <summary>Base class for server-side implementations of Greeter</summary>
- public abstract partial class GreeterBase
- {
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request received from the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>The response to send back to the client (wrapped by a task).</returns>
- public virtual global::System.Threading.Tasks.Task<global::Helloworld.HelloReply> SayHello(global::Helloworld.HelloRequest request, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- }
-
- /// <summary>Client for Greeter</summary>
- public partial class GreeterClient : grpc::ClientBase<GreeterClient>
- {
- /// <summary>Creates a new client for Greeter</summary>
- /// <param name="channel">The channel to use to make remote calls.</param>
- public GreeterClient(grpc::Channel channel) : base(channel)
- {
- }
- /// <summary>Creates a new client for Greeter that uses a custom <c>CallInvoker</c>.</summary>
- /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
- public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker)
- {
- }
- /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
- protected GreeterClient() : base()
- {
- }
- /// <summary>Protected constructor to allow creation of configured clients.</summary>
- /// <param name="configuration">The client configuration.</param>
- protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration)
- {
- }
-
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::CallOptions options)
- {
- return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request);
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::CallOptions options)
- {
- return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request);
- }
- /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
- protected override GreeterClient NewInstance(ClientBaseConfiguration configuration)
- {
- return new GreeterClient(configuration);
- }
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
- public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl)
- {
- return grpc::ServerServiceDefinition.CreateBuilder()
- .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build();
- }
-
- }
-}
-#endregion
diff --git a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
index 24a89d58c5..ac10d85497 100644
--- a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
+++ b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
@@ -1,12 +1,8 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>GreeterClient</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>GreeterClient</AssemblyName>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
- <PackageId>GreeterClient</PackageId>
</PropertyGroup>
<ItemGroup>
diff --git a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
index 9ea1fa3817..ac10d85497 100644
--- a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
+++ b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
@@ -1,12 +1,8 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>GreeterServer</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>GreeterServer</AssemblyName>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
- <PackageId>GreeterServer</PackageId>
</PropertyGroup>
<ItemGroup>
diff --git a/examples/csharp/Helloworld/README.md b/examples/csharp/Helloworld/README.md
index 4871132426..e4771ee91a 100644
--- a/examples/csharp/Helloworld/README.md
+++ b/examples/csharp/Helloworld/README.md
@@ -3,41 +3,31 @@ gRPC in 3 minutes (C#)
BACKGROUND
-------------
-For this sample, we've already generated the server and client stubs from [helloworld.proto][].
-
-Example projects in this directory depend on the [Grpc](https://www.nuget.org/packages/Grpc/)
-and [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/) NuGet packages
-which have been already added to the project for you.
+This is a version of the helloworld example using the dotnet SDK
+tools to compile [helloworld.proto][] in a common library, build the server
+and the client, and run them.
PREREQUISITES
-------------
- The [.NET Core SDK 2.1+](https://www.microsoft.com/net/core)
-You can also build the example directly using Visual Studio 2017, but it's not a requirement.
-
-BUILD
--------
-
-From the `examples/csharp/Helloworld` directory:
+You can also build the solution `Greeter.sln` using Visual Studio 2017,
+but it's not a requirement.
-- `dotnet build Greeter.sln`
-
-Try it!
--------
+BUILD AND RUN
+-------------
-- Run the server
+- Build and run the server
```
- > cd GreeterServer
- > dotnet run -f netcoreapp2.1
+ > dotnet run -p GreeterServer
```
-- Run the client
+- Build and run the client
```
- > cd GreeterClient
- > dotnet run -f netcoreapp2.1
+ > dotnet run -p GreeterClient
```
Tutorial
diff --git a/examples/csharp/Helloworld/generate_protos.bat b/examples/csharp/Helloworld/generate_protos.bat
deleted file mode 100644
index ab0c0eb46a..0000000000
--- a/examples/csharp/Helloworld/generate_protos.bat
+++ /dev/null
@@ -1,28 +0,0 @@
-@rem Copyright 2016 gRPC authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-
-@rem Generate the C# code for .proto files
-
-setlocal
-
-@rem enter this directory
-cd /d %~dp0
-
-@rem packages will be available in nuget cache directory once the project is built or after "dotnet restore"
-set PROTOC=%UserProfile%\.nuget\packages\Google.Protobuf.Tools\3.6.1\tools\windows_x64\protoc.exe
-set PLUGIN=%UserProfile%\.nuget\packages\Grpc.Tools\1.14.1\tools\windows_x64\grpc_csharp_plugin.exe
-
-%PROTOC% -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%PLUGIN%
-
-endlocal
diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter.sln b/examples/csharp/HelloworldLegacyCsproj/Greeter.sln
index 49e364d91c..26cae7a727 100644
--- a/examples/csharp/HelloworldLegacyCsproj/Greeter.sln
+++ b/examples/csharp/HelloworldLegacyCsproj/Greeter.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj b/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj
index 197a9fb625..da15ba3954 100644
--- a/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj
+++ b/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj
@@ -1,5 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.props" Condition="Exists('..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -36,7 +37,7 @@
<HintPath>..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
- <HintPath>..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll</HintPath>
+ <HintPath>..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
@@ -47,25 +48,23 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Helloworld.cs" />
- <Compile Include="HelloworldGrpc.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
- <None Include="..\..\..\protos\helloworld.proto">
+ <Protobuf Include="..\..\..\protos\helloworld.proto">
<Link>protos\helloworld.proto</Link>
- </None>
- <None Include="..\generate_protos.bat">
- <Link>generate_protos.bat</Link>
- </None>
+ </Protobuf>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
- <Import Project="..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" />
+ <Import Project="..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.props'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.targets'))" />
</Target>
-</Project> \ No newline at end of file
+ <Import Project="..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.targets" Condition="Exists('..\packages\Grpc.Tools.1.17.0\build\Grpc.Tools.targets')" />
+</Project>
diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs b/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs
deleted file mode 100644
index e008ec27e5..0000000000
--- a/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs
+++ /dev/null
@@ -1,312 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: helloworld.proto
-// </auto-generated>
-#pragma warning disable 1591, 0612, 3021
-#region Designer generated code
-
-using pb = global::Google.Protobuf;
-using pbc = global::Google.Protobuf.Collections;
-using pbr = global::Google.Protobuf.Reflection;
-using scg = global::System.Collections.Generic;
-namespace Helloworld {
-
- /// <summary>Holder for reflection information generated from helloworld.proto</summary>
- public static partial class HelloworldReflection {
-
- #region Descriptor
- /// <summary>File descriptor for helloworld.proto</summary>
- public static pbr::FileDescriptor Descriptor {
- get { return descriptor; }
- }
- private static pbr::FileDescriptor descriptor;
-
- static HelloworldReflection() {
- byte[] descriptorData = global::System.Convert.FromBase64String(
- string.Concat(
- "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz",
- "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo",
- "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl",
- "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4",
- "YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw",
- "cm90bzM="));
- descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
- new pbr::FileDescriptor[] { },
- new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
- new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null)
- }));
- }
- #endregion
-
- }
- #region Messages
- /// <summary>
- /// The request message containing the user's name.
- /// </summary>
- public sealed partial class HelloRequest : pb::IMessage<HelloRequest> {
- private static readonly pb::MessageParser<HelloRequest> _parser = new pb::MessageParser<HelloRequest>(() => new HelloRequest());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<HelloRequest> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest(HelloRequest other) : this() {
- name_ = other.name_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloRequest Clone() {
- return new HelloRequest(this);
- }
-
- /// <summary>Field number for the "name" field.</summary>
- public const int NameFieldNumber = 1;
- private string name_ = "";
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Name {
- get { return name_; }
- set {
- name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as HelloRequest);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(HelloRequest other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Name != other.Name) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Name.Length != 0) hash ^= Name.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Name.Length != 0) {
- output.WriteRawTag(10);
- output.WriteString(Name);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Name.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(HelloRequest other) {
- if (other == null) {
- return;
- }
- if (other.Name.Length != 0) {
- Name = other.Name;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- Name = input.ReadString();
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// The response message containing the greetings
- /// </summary>
- public sealed partial class HelloReply : pb::IMessage<HelloReply> {
- private static readonly pb::MessageParser<HelloReply> _parser = new pb::MessageParser<HelloReply>(() => new HelloReply());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<HelloReply> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply(HelloReply other) : this() {
- message_ = other.message_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public HelloReply Clone() {
- return new HelloReply(this);
- }
-
- /// <summary>Field number for the "message" field.</summary>
- public const int MessageFieldNumber = 1;
- private string message_ = "";
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Message {
- get { return message_; }
- set {
- message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as HelloReply);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(HelloReply other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Message != other.Message) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Message.Length != 0) hash ^= Message.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Message.Length != 0) {
- output.WriteRawTag(10);
- output.WriteString(Message);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Message.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(HelloReply other) {
- if (other == null) {
- return;
- }
- if (other.Message.Length != 0) {
- Message = other.Message;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- Message = input.ReadString();
- break;
- }
- }
- }
- }
-
- }
-
- #endregion
-
-}
-
-#endregion Designer generated code
diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs b/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs
deleted file mode 100644
index d6b959adc6..0000000000
--- a/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: helloworld.proto
-// </auto-generated>
-// Original file comments:
-// Copyright 2015 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#pragma warning disable 0414, 1591
-#region Designer generated code
-
-using grpc = global::Grpc.Core;
-
-namespace Helloworld {
- /// <summary>
- /// The greeting service definition.
- /// </summary>
- public static partial class Greeter
- {
- static readonly string __ServiceName = "helloworld.Greeter";
-
- static readonly grpc::Marshaller<global::Helloworld.HelloRequest> __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Helloworld.HelloReply> __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom);
-
- static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
- grpc::MethodType.Unary,
- __ServiceName,
- "SayHello",
- __Marshaller_helloworld_HelloRequest,
- __Marshaller_helloworld_HelloReply);
-
- /// <summary>Service descriptor</summary>
- public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
- {
- get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; }
- }
-
- /// <summary>Base class for server-side implementations of Greeter</summary>
- public abstract partial class GreeterBase
- {
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request received from the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>The response to send back to the client (wrapped by a task).</returns>
- public virtual global::System.Threading.Tasks.Task<global::Helloworld.HelloReply> SayHello(global::Helloworld.HelloRequest request, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- }
-
- /// <summary>Client for Greeter</summary>
- public partial class GreeterClient : grpc::ClientBase<GreeterClient>
- {
- /// <summary>Creates a new client for Greeter</summary>
- /// <param name="channel">The channel to use to make remote calls.</param>
- public GreeterClient(grpc::Channel channel) : base(channel)
- {
- }
- /// <summary>Creates a new client for Greeter that uses a custom <c>CallInvoker</c>.</summary>
- /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
- public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker)
- {
- }
- /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
- protected GreeterClient() : base()
- {
- }
- /// <summary>Protected constructor to allow creation of configured clients.</summary>
- /// <param name="configuration">The client configuration.</param>
- protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration)
- {
- }
-
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::CallOptions options)
- {
- return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request);
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// Sends a greeting
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::CallOptions options)
- {
- return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request);
- }
- /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
- protected override GreeterClient NewInstance(ClientBaseConfiguration configuration)
- {
- return new GreeterClient(configuration);
- }
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
- public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl)
- {
- return grpc::ServerServiceDefinition.CreateBuilder()
- .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build();
- }
-
- }
-}
-#endregion
diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config b/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config
index 23857be22f..154b599321 100644
--- a/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config
+++ b/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Google.Protobuf" version="3.6.1" targetFramework="net45" />
- <package id="Grpc" version="1.14.1" targetFramework="net45" />
- <package id="Grpc.Core" version="1.14.1" targetFramework="net45" />
- <package id="Grpc.Tools" version="1.14.1" targetFramework="net45" />
+ <package id="Grpc" version="1.17.0" targetFramework="net45" />
+ <package id="Grpc.Core" version="1.17.0" targetFramework="net45" />
+ <package id="Grpc.Tools" version="1.17.0" targetFramework="net45" developmentDependency="true" />
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages> \ No newline at end of file
+</packages>
diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj
index 3bb7ff1ee1..31a3a90345 100644
--- a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj
+++ b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -36,7 +36,7 @@
<HintPath>..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
- <HintPath>..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll</HintPath>
+ <HintPath>..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
@@ -59,11 +59,11 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" />
+ <Import Project="..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets'))" />
</Target>
</Project> \ No newline at end of file
diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config
index df4df8282c..2fd8228689 100644
--- a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config
+++ b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Google.Protobuf" version="3.6.1" targetFramework="net45" />
- <package id="Grpc" version="1.14.1" targetFramework="net45" />
- <package id="Grpc.Core" version="1.14.1" targetFramework="net45" />
+ <package id="Grpc" version="1.17.0" targetFramework="net45" />
+ <package id="Grpc.Core" version="1.17.0" targetFramework="net45" />
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj
index 4396b04efe..27ca963040 100644
--- a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj
+++ b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -36,7 +36,7 @@
<HintPath>..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
- <HintPath>..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll</HintPath>
+ <HintPath>..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
@@ -59,11 +59,11 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" />
+ <Import Project="..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.14.1\build\net45\Grpc.Core.targets'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.1.17.0\build\net45\Grpc.Core.targets'))" />
</Target>
</Project> \ No newline at end of file
diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config
index df4df8282c..2fd8228689 100644
--- a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config
+++ b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Google.Protobuf" version="3.6.1" targetFramework="net45" />
- <package id="Grpc" version="1.14.1" targetFramework="net45" />
- <package id="Grpc.Core" version="1.14.1" targetFramework="net45" />
+ <package id="Grpc" version="1.17.0" targetFramework="net45" />
+ <package id="Grpc.Core" version="1.17.0" targetFramework="net45" />
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/examples/csharp/HelloworldLegacyCsproj/README.md b/examples/csharp/HelloworldLegacyCsproj/README.md
index 6d42c5ef25..60b09e0925 100644
--- a/examples/csharp/HelloworldLegacyCsproj/README.md
+++ b/examples/csharp/HelloworldLegacyCsproj/README.md
@@ -3,21 +3,21 @@ gRPC in 3 minutes (C#)
BACKGROUND
-------------
-This is a different version of the helloworld example, using the old-style .csproj
-files supported by VS2013 and VS2015 (and older versions of mono).
-You can still use gRPC with the old-style .csproj files, but [using the new-style
-.csproj projects](../helloworld/README.md) (supported by VS2017 and dotnet SDK) is recommended.
-
-For this sample, we've already generated the server and client stubs from [helloworld.proto][].
-
-Example projects depend on the [Grpc](https://www.nuget.org/packages/Grpc/), [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/)
+This is a different version of the helloworld example, using the "classic" .csproj
+files, the only format supported by VS2013 (and older versions of mono).
+You can still use gRPC with the classic .csproj files, but [using the new-style
+.csproj projects](../helloworld/README.md) (supported by VS2015 Update3 and above,
+and dotnet SDK) is recommended.
+
+Example projects depend on the [Grpc](https://www.nuget.org/packages/Grpc/),
+[Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/)
and [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/) NuGet packages
which have been already added to the project for you.
PREREQUISITES
-------------
-- Windows: .NET Framework 4.5+, Visual Studio 2013 or 2015
+- Windows: .NET Framework 4.5+, Visual Studio 2013 or higher
- Linux: Mono 4+, MonoDevelop 5.9+
- Mac OS X: Xamarin Studio 5.9+
@@ -28,12 +28,15 @@ BUILD
# Using Visual Studio
-* Build the solution (this will automatically download NuGet dependencies)
+* Select "Restore NuGet Packages" from the solution context menu. It is recommended
+ to close and re-open the solution after the packages have been restored from
+ Visual Studio.
+* Build the solution.
# Using Monodevelop or Xamarin Studio
-The nuget add-in available for Xamarin Studio and Monodevelop IDEs is too old to
-download all of the nuget dependencies of gRPC.
+The NuGet add-in available for Xamarin Studio and Monodevelop IDEs is too old to
+download all of the NuGet dependencies of gRPC.
Using these IDEs, a workaround is as follows:
* Obtain a nuget executable for your platform and update it with
diff --git a/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat b/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat
deleted file mode 100644
index d1e7160f91..0000000000
--- a/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat
+++ /dev/null
@@ -1,26 +0,0 @@
-@rem Copyright 2016 gRPC authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-
-@rem Generate the C# code for .proto files
-
-setlocal
-
-@rem enter this directory
-cd /d %~dp0
-
-set TOOLS_PATH=packages\Grpc.Tools.1.14.1\tools\windows_x86
-
-%TOOLS_PATH%\protoc.exe -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe
-
-endlocal
diff --git a/examples/csharp/RouteGuide/RouteGuide.sln b/examples/csharp/RouteGuide/RouteGuide.sln
index 73e6e306b1..5e103294a5 100644
--- a/examples/csharp/RouteGuide/RouteGuide.sln
+++ b/examples/csharp/RouteGuide/RouteGuide.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs
deleted file mode 100644
index 10c9aec5f8..0000000000
--- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs
+++ /dev/null
@@ -1,981 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: route_guide.proto
-// </auto-generated>
-#pragma warning disable 1591, 0612, 3021
-#region Designer generated code
-
-using pb = global::Google.Protobuf;
-using pbc = global::Google.Protobuf.Collections;
-using pbr = global::Google.Protobuf.Reflection;
-using scg = global::System.Collections.Generic;
-namespace Routeguide {
-
- /// <summary>Holder for reflection information generated from route_guide.proto</summary>
- public static partial class RouteGuideReflection {
-
- #region Descriptor
- /// <summary>File descriptor for route_guide.proto</summary>
- public static pbr::FileDescriptor Descriptor {
- get { return descriptor; }
- }
- private static pbr::FileDescriptor descriptor;
-
- static RouteGuideReflection() {
- byte[] descriptorData = global::System.Convert.FromBase64String(
- string.Concat(
- "ChFyb3V0ZV9ndWlkZS5wcm90bxIKcm91dGVndWlkZSIsCgVQb2ludBIQCghs",
- "YXRpdHVkZRgBIAEoBRIRCglsb25naXR1ZGUYAiABKAUiSQoJUmVjdGFuZ2xl",
- "Eh0KAmxvGAEgASgLMhEucm91dGVndWlkZS5Qb2ludBIdCgJoaRgCIAEoCzIR",
- "LnJvdXRlZ3VpZGUuUG9pbnQiPAoHRmVhdHVyZRIMCgRuYW1lGAEgASgJEiMK",
- "CGxvY2F0aW9uGAIgASgLMhEucm91dGVndWlkZS5Qb2ludCJBCglSb3V0ZU5v",
- "dGUSIwoIbG9jYXRpb24YASABKAsyES5yb3V0ZWd1aWRlLlBvaW50Eg8KB21l",
- "c3NhZ2UYAiABKAkiYgoMUm91dGVTdW1tYXJ5EhMKC3BvaW50X2NvdW50GAEg",
- "ASgFEhUKDWZlYXR1cmVfY291bnQYAiABKAUSEAoIZGlzdGFuY2UYAyABKAUS",
- "FAoMZWxhcHNlZF90aW1lGAQgASgFMoUCCgpSb3V0ZUd1aWRlEjYKCkdldEZl",
- "YXR1cmUSES5yb3V0ZWd1aWRlLlBvaW50GhMucm91dGVndWlkZS5GZWF0dXJl",
- "IgASPgoMTGlzdEZlYXR1cmVzEhUucm91dGVndWlkZS5SZWN0YW5nbGUaEy5y",
- "b3V0ZWd1aWRlLkZlYXR1cmUiADABEj4KC1JlY29yZFJvdXRlEhEucm91dGVn",
- "dWlkZS5Qb2ludBoYLnJvdXRlZ3VpZGUuUm91dGVTdW1tYXJ5IgAoARI/CglS",
- "b3V0ZUNoYXQSFS5yb3V0ZWd1aWRlLlJvdXRlTm90ZRoVLnJvdXRlZ3VpZGUu",
- "Um91dGVOb3RlIgAoATABQjYKG2lvLmdycGMuZXhhbXBsZXMucm91dGVndWlk",
- "ZUIPUm91dGVHdWlkZVByb3RvUAGiAgNSVEdiBnByb3RvMw=="));
- descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
- new pbr::FileDescriptor[] { },
- new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
- new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Point), global::Routeguide.Point.Parser, new[]{ "Latitude", "Longitude" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Rectangle), global::Routeguide.Rectangle.Parser, new[]{ "Lo", "Hi" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Feature), global::Routeguide.Feature.Parser, new[]{ "Name", "Location" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteNote), global::Routeguide.RouteNote.Parser, new[]{ "Location", "Message" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteSummary), global::Routeguide.RouteSummary.Parser, new[]{ "PointCount", "FeatureCount", "Distance", "ElapsedTime" }, null, null, null)
- }));
- }
- #endregion
-
- }
- #region Messages
- /// <summary>
- /// Points are represented as latitude-longitude pairs in the E7 representation
- /// (degrees multiplied by 10**7 and rounded to the nearest integer).
- /// Latitudes should be in the range +/- 90 degrees and longitude should be in
- /// the range +/- 180 degrees (inclusive).
- /// </summary>
- public sealed partial class Point : pb::IMessage<Point> {
- private static readonly pb::MessageParser<Point> _parser = new pb::MessageParser<Point>(() => new Point());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<Point> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[0]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Point() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Point(Point other) : this() {
- latitude_ = other.latitude_;
- longitude_ = other.longitude_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Point Clone() {
- return new Point(this);
- }
-
- /// <summary>Field number for the "latitude" field.</summary>
- public const int LatitudeFieldNumber = 1;
- private int latitude_;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int Latitude {
- get { return latitude_; }
- set {
- latitude_ = value;
- }
- }
-
- /// <summary>Field number for the "longitude" field.</summary>
- public const int LongitudeFieldNumber = 2;
- private int longitude_;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int Longitude {
- get { return longitude_; }
- set {
- longitude_ = value;
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as Point);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(Point other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Latitude != other.Latitude) return false;
- if (Longitude != other.Longitude) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Latitude != 0) hash ^= Latitude.GetHashCode();
- if (Longitude != 0) hash ^= Longitude.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Latitude != 0) {
- output.WriteRawTag(8);
- output.WriteInt32(Latitude);
- }
- if (Longitude != 0) {
- output.WriteRawTag(16);
- output.WriteInt32(Longitude);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Latitude != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(Latitude);
- }
- if (Longitude != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(Longitude);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(Point other) {
- if (other == null) {
- return;
- }
- if (other.Latitude != 0) {
- Latitude = other.Latitude;
- }
- if (other.Longitude != 0) {
- Longitude = other.Longitude;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 8: {
- Latitude = input.ReadInt32();
- break;
- }
- case 16: {
- Longitude = input.ReadInt32();
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// A latitude-longitude rectangle, represented as two diagonally opposite
- /// points "lo" and "hi".
- /// </summary>
- public sealed partial class Rectangle : pb::IMessage<Rectangle> {
- private static readonly pb::MessageParser<Rectangle> _parser = new pb::MessageParser<Rectangle>(() => new Rectangle());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<Rectangle> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[1]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Rectangle() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Rectangle(Rectangle other) : this() {
- lo_ = other.lo_ != null ? other.lo_.Clone() : null;
- hi_ = other.hi_ != null ? other.hi_.Clone() : null;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Rectangle Clone() {
- return new Rectangle(this);
- }
-
- /// <summary>Field number for the "lo" field.</summary>
- public const int LoFieldNumber = 1;
- private global::Routeguide.Point lo_;
- /// <summary>
- /// One corner of the rectangle.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public global::Routeguide.Point Lo {
- get { return lo_; }
- set {
- lo_ = value;
- }
- }
-
- /// <summary>Field number for the "hi" field.</summary>
- public const int HiFieldNumber = 2;
- private global::Routeguide.Point hi_;
- /// <summary>
- /// The other corner of the rectangle.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public global::Routeguide.Point Hi {
- get { return hi_; }
- set {
- hi_ = value;
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as Rectangle);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(Rectangle other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (!object.Equals(Lo, other.Lo)) return false;
- if (!object.Equals(Hi, other.Hi)) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (lo_ != null) hash ^= Lo.GetHashCode();
- if (hi_ != null) hash ^= Hi.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (lo_ != null) {
- output.WriteRawTag(10);
- output.WriteMessage(Lo);
- }
- if (hi_ != null) {
- output.WriteRawTag(18);
- output.WriteMessage(Hi);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (lo_ != null) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Lo);
- }
- if (hi_ != null) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Hi);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(Rectangle other) {
- if (other == null) {
- return;
- }
- if (other.lo_ != null) {
- if (lo_ == null) {
- lo_ = new global::Routeguide.Point();
- }
- Lo.MergeFrom(other.Lo);
- }
- if (other.hi_ != null) {
- if (hi_ == null) {
- hi_ = new global::Routeguide.Point();
- }
- Hi.MergeFrom(other.Hi);
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- if (lo_ == null) {
- lo_ = new global::Routeguide.Point();
- }
- input.ReadMessage(lo_);
- break;
- }
- case 18: {
- if (hi_ == null) {
- hi_ = new global::Routeguide.Point();
- }
- input.ReadMessage(hi_);
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// A feature names something at a given point.
- ///
- /// If a feature could not be named, the name is empty.
- /// </summary>
- public sealed partial class Feature : pb::IMessage<Feature> {
- private static readonly pb::MessageParser<Feature> _parser = new pb::MessageParser<Feature>(() => new Feature());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<Feature> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[2]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Feature() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Feature(Feature other) : this() {
- name_ = other.name_;
- location_ = other.location_ != null ? other.location_.Clone() : null;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public Feature Clone() {
- return new Feature(this);
- }
-
- /// <summary>Field number for the "name" field.</summary>
- public const int NameFieldNumber = 1;
- private string name_ = "";
- /// <summary>
- /// The name of the feature.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Name {
- get { return name_; }
- set {
- name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- /// <summary>Field number for the "location" field.</summary>
- public const int LocationFieldNumber = 2;
- private global::Routeguide.Point location_;
- /// <summary>
- /// The point where the feature is detected.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public global::Routeguide.Point Location {
- get { return location_; }
- set {
- location_ = value;
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as Feature);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(Feature other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (Name != other.Name) return false;
- if (!object.Equals(Location, other.Location)) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (Name.Length != 0) hash ^= Name.GetHashCode();
- if (location_ != null) hash ^= Location.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (Name.Length != 0) {
- output.WriteRawTag(10);
- output.WriteString(Name);
- }
- if (location_ != null) {
- output.WriteRawTag(18);
- output.WriteMessage(Location);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (Name.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
- }
- if (location_ != null) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(Feature other) {
- if (other == null) {
- return;
- }
- if (other.Name.Length != 0) {
- Name = other.Name;
- }
- if (other.location_ != null) {
- if (location_ == null) {
- location_ = new global::Routeguide.Point();
- }
- Location.MergeFrom(other.Location);
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- Name = input.ReadString();
- break;
- }
- case 18: {
- if (location_ == null) {
- location_ = new global::Routeguide.Point();
- }
- input.ReadMessage(location_);
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// A RouteNote is a message sent while at a given point.
- /// </summary>
- public sealed partial class RouteNote : pb::IMessage<RouteNote> {
- private static readonly pb::MessageParser<RouteNote> _parser = new pb::MessageParser<RouteNote>(() => new RouteNote());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<RouteNote> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[3]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteNote() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteNote(RouteNote other) : this() {
- location_ = other.location_ != null ? other.location_.Clone() : null;
- message_ = other.message_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteNote Clone() {
- return new RouteNote(this);
- }
-
- /// <summary>Field number for the "location" field.</summary>
- public const int LocationFieldNumber = 1;
- private global::Routeguide.Point location_;
- /// <summary>
- /// The location from which the message is sent.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public global::Routeguide.Point Location {
- get { return location_; }
- set {
- location_ = value;
- }
- }
-
- /// <summary>Field number for the "message" field.</summary>
- public const int MessageFieldNumber = 2;
- private string message_ = "";
- /// <summary>
- /// The message to be sent.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public string Message {
- get { return message_; }
- set {
- message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as RouteNote);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(RouteNote other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (!object.Equals(Location, other.Location)) return false;
- if (Message != other.Message) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (location_ != null) hash ^= Location.GetHashCode();
- if (Message.Length != 0) hash ^= Message.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (location_ != null) {
- output.WriteRawTag(10);
- output.WriteMessage(Location);
- }
- if (Message.Length != 0) {
- output.WriteRawTag(18);
- output.WriteString(Message);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (location_ != null) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location);
- }
- if (Message.Length != 0) {
- size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(RouteNote other) {
- if (other == null) {
- return;
- }
- if (other.location_ != null) {
- if (location_ == null) {
- location_ = new global::Routeguide.Point();
- }
- Location.MergeFrom(other.Location);
- }
- if (other.Message.Length != 0) {
- Message = other.Message;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 10: {
- if (location_ == null) {
- location_ = new global::Routeguide.Point();
- }
- input.ReadMessage(location_);
- break;
- }
- case 18: {
- Message = input.ReadString();
- break;
- }
- }
- }
- }
-
- }
-
- /// <summary>
- /// A RouteSummary is received in response to a RecordRoute rpc.
- ///
- /// It contains the number of individual points received, the number of
- /// detected features, and the total distance covered as the cumulative sum of
- /// the distance between each point.
- /// </summary>
- public sealed partial class RouteSummary : pb::IMessage<RouteSummary> {
- private static readonly pb::MessageParser<RouteSummary> _parser = new pb::MessageParser<RouteSummary>(() => new RouteSummary());
- private pb::UnknownFieldSet _unknownFields;
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pb::MessageParser<RouteSummary> Parser { get { return _parser; } }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[4]; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteSummary() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteSummary(RouteSummary other) : this() {
- pointCount_ = other.pointCount_;
- featureCount_ = other.featureCount_;
- distance_ = other.distance_;
- elapsedTime_ = other.elapsedTime_;
- _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public RouteSummary Clone() {
- return new RouteSummary(this);
- }
-
- /// <summary>Field number for the "point_count" field.</summary>
- public const int PointCountFieldNumber = 1;
- private int pointCount_;
- /// <summary>
- /// The number of points received.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int PointCount {
- get { return pointCount_; }
- set {
- pointCount_ = value;
- }
- }
-
- /// <summary>Field number for the "feature_count" field.</summary>
- public const int FeatureCountFieldNumber = 2;
- private int featureCount_;
- /// <summary>
- /// The number of known features passed while traversing the route.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int FeatureCount {
- get { return featureCount_; }
- set {
- featureCount_ = value;
- }
- }
-
- /// <summary>Field number for the "distance" field.</summary>
- public const int DistanceFieldNumber = 3;
- private int distance_;
- /// <summary>
- /// The distance covered in metres.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int Distance {
- get { return distance_; }
- set {
- distance_ = value;
- }
- }
-
- /// <summary>Field number for the "elapsed_time" field.</summary>
- public const int ElapsedTimeFieldNumber = 4;
- private int elapsedTime_;
- /// <summary>
- /// The duration of the traversal in seconds.
- /// </summary>
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int ElapsedTime {
- get { return elapsedTime_; }
- set {
- elapsedTime_ = value;
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override bool Equals(object other) {
- return Equals(other as RouteSummary);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public bool Equals(RouteSummary other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (PointCount != other.PointCount) return false;
- if (FeatureCount != other.FeatureCount) return false;
- if (Distance != other.Distance) return false;
- if (ElapsedTime != other.ElapsedTime) return false;
- return Equals(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override int GetHashCode() {
- int hash = 1;
- if (PointCount != 0) hash ^= PointCount.GetHashCode();
- if (FeatureCount != 0) hash ^= FeatureCount.GetHashCode();
- if (Distance != 0) hash ^= Distance.GetHashCode();
- if (ElapsedTime != 0) hash ^= ElapsedTime.GetHashCode();
- if (_unknownFields != null) {
- hash ^= _unknownFields.GetHashCode();
- }
- return hash;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void WriteTo(pb::CodedOutputStream output) {
- if (PointCount != 0) {
- output.WriteRawTag(8);
- output.WriteInt32(PointCount);
- }
- if (FeatureCount != 0) {
- output.WriteRawTag(16);
- output.WriteInt32(FeatureCount);
- }
- if (Distance != 0) {
- output.WriteRawTag(24);
- output.WriteInt32(Distance);
- }
- if (ElapsedTime != 0) {
- output.WriteRawTag(32);
- output.WriteInt32(ElapsedTime);
- }
- if (_unknownFields != null) {
- _unknownFields.WriteTo(output);
- }
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public int CalculateSize() {
- int size = 0;
- if (PointCount != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(PointCount);
- }
- if (FeatureCount != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(FeatureCount);
- }
- if (Distance != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(Distance);
- }
- if (ElapsedTime != 0) {
- size += 1 + pb::CodedOutputStream.ComputeInt32Size(ElapsedTime);
- }
- if (_unknownFields != null) {
- size += _unknownFields.CalculateSize();
- }
- return size;
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(RouteSummary other) {
- if (other == null) {
- return;
- }
- if (other.PointCount != 0) {
- PointCount = other.PointCount;
- }
- if (other.FeatureCount != 0) {
- FeatureCount = other.FeatureCount;
- }
- if (other.Distance != 0) {
- Distance = other.Distance;
- }
- if (other.ElapsedTime != 0) {
- ElapsedTime = other.ElapsedTime;
- }
- _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
- break;
- case 8: {
- PointCount = input.ReadInt32();
- break;
- }
- case 16: {
- FeatureCount = input.ReadInt32();
- break;
- }
- case 24: {
- Distance = input.ReadInt32();
- break;
- }
- case 32: {
- ElapsedTime = input.ReadInt32();
- break;
- }
- }
- }
- }
-
- }
-
- #endregion
-
-}
-
-#endregion Designer generated code
diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
index 86346d1e14..4c6949488c 100644
--- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
+++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
@@ -1,25 +1,22 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>RouteGuide</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>RouteGuide</AssemblyName>
- <PackageId>RouteGuide</PackageId>
+ <TargetFramework>netstandard1.5</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
- <PackageReference Include="Google.Protobuf.Tools" Version="3.6.1" />
- <PackageReference Include="Grpc" Version="1.14.1" />
- <PackageReference Include="Grpc.Tools" Version="1.14.1" />
+ <PackageReference Include="Grpc" Version="1.17.0" />
+ <PackageReference Include="Grpc.Tools" Version="1.17.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
- <None Include="route_guide_db.json">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
+ <Protobuf Include="..\..\..\protos\route_guide.proto" Link="protos\route_guide.proto" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <None Include="route_guide_db.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs
deleted file mode 100644
index 445708e446..0000000000
--- a/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs
+++ /dev/null
@@ -1,331 +0,0 @@
-// <auto-generated>
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: route_guide.proto
-// </auto-generated>
-// Original file comments:
-// Copyright 2015 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#pragma warning disable 0414, 1591
-#region Designer generated code
-
-using grpc = global::Grpc.Core;
-
-namespace Routeguide {
- /// <summary>
- /// Interface exported by the server.
- /// </summary>
- public static partial class RouteGuide
- {
- static readonly string __ServiceName = "routeguide.RouteGuide";
-
- static readonly grpc::Marshaller<global::Routeguide.Point> __Marshaller_routeguide_Point = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Point.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Routeguide.Feature> __Marshaller_routeguide_Feature = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Feature.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Routeguide.Rectangle> __Marshaller_routeguide_Rectangle = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Rectangle.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Routeguide.RouteSummary> __Marshaller_routeguide_RouteSummary = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteSummary.Parser.ParseFrom);
- static readonly grpc::Marshaller<global::Routeguide.RouteNote> __Marshaller_routeguide_RouteNote = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteNote.Parser.ParseFrom);
-
- static readonly grpc::Method<global::Routeguide.Point, global::Routeguide.Feature> __Method_GetFeature = new grpc::Method<global::Routeguide.Point, global::Routeguide.Feature>(
- grpc::MethodType.Unary,
- __ServiceName,
- "GetFeature",
- __Marshaller_routeguide_Point,
- __Marshaller_routeguide_Feature);
-
- static readonly grpc::Method<global::Routeguide.Rectangle, global::Routeguide.Feature> __Method_ListFeatures = new grpc::Method<global::Routeguide.Rectangle, global::Routeguide.Feature>(
- grpc::MethodType.ServerStreaming,
- __ServiceName,
- "ListFeatures",
- __Marshaller_routeguide_Rectangle,
- __Marshaller_routeguide_Feature);
-
- static readonly grpc::Method<global::Routeguide.Point, global::Routeguide.RouteSummary> __Method_RecordRoute = new grpc::Method<global::Routeguide.Point, global::Routeguide.RouteSummary>(
- grpc::MethodType.ClientStreaming,
- __ServiceName,
- "RecordRoute",
- __Marshaller_routeguide_Point,
- __Marshaller_routeguide_RouteSummary);
-
- static readonly grpc::Method<global::Routeguide.RouteNote, global::Routeguide.RouteNote> __Method_RouteChat = new grpc::Method<global::Routeguide.RouteNote, global::Routeguide.RouteNote>(
- grpc::MethodType.DuplexStreaming,
- __ServiceName,
- "RouteChat",
- __Marshaller_routeguide_RouteNote,
- __Marshaller_routeguide_RouteNote);
-
- /// <summary>Service descriptor</summary>
- public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
- {
- get { return global::Routeguide.RouteGuideReflection.Descriptor.Services[0]; }
- }
-
- /// <summary>Base class for server-side implementations of RouteGuide</summary>
- public abstract partial class RouteGuideBase
- {
- /// <summary>
- /// A simple RPC.
- ///
- /// Obtains the feature at a given position.
- ///
- /// A feature with an empty name is returned if there's no feature at the given
- /// position.
- /// </summary>
- /// <param name="request">The request received from the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>The response to send back to the client (wrapped by a task).</returns>
- public virtual global::System.Threading.Tasks.Task<global::Routeguide.Feature> GetFeature(global::Routeguide.Point request, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- /// <summary>
- /// A server-to-client streaming RPC.
- ///
- /// Obtains the Features available within the given Rectangle. Results are
- /// streamed rather than returned at once (e.g. in a response message with a
- /// repeated field), as the rectangle may cover a large area and contain a
- /// huge number of features.
- /// </summary>
- /// <param name="request">The request received from the client.</param>
- /// <param name="responseStream">Used for sending responses back to the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>A task indicating completion of the handler.</returns>
- public virtual global::System.Threading.Tasks.Task ListFeatures(global::Routeguide.Rectangle request, grpc::IServerStreamWriter<global::Routeguide.Feature> responseStream, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- /// <summary>
- /// A client-to-server streaming RPC.
- ///
- /// Accepts a stream of Points on a route being traversed, returning a
- /// RouteSummary when traversal is completed.
- /// </summary>
- /// <param name="requestStream">Used for reading requests from the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>The response to send back to the client (wrapped by a task).</returns>
- public virtual global::System.Threading.Tasks.Task<global::Routeguide.RouteSummary> RecordRoute(grpc::IAsyncStreamReader<global::Routeguide.Point> requestStream, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- /// <summary>
- /// A Bidirectional streaming RPC.
- ///
- /// Accepts a stream of RouteNotes sent while a route is being traversed,
- /// while receiving other RouteNotes (e.g. from other users).
- /// </summary>
- /// <param name="requestStream">Used for reading requests from the client.</param>
- /// <param name="responseStream">Used for sending responses back to the client.</param>
- /// <param name="context">The context of the server-side call handler being invoked.</param>
- /// <returns>A task indicating completion of the handler.</returns>
- public virtual global::System.Threading.Tasks.Task RouteChat(grpc::IAsyncStreamReader<global::Routeguide.RouteNote> requestStream, grpc::IServerStreamWriter<global::Routeguide.RouteNote> responseStream, grpc::ServerCallContext context)
- {
- throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
- }
-
- }
-
- /// <summary>Client for RouteGuide</summary>
- public partial class RouteGuideClient : grpc::ClientBase<RouteGuideClient>
- {
- /// <summary>Creates a new client for RouteGuide</summary>
- /// <param name="channel">The channel to use to make remote calls.</param>
- public RouteGuideClient(grpc::Channel channel) : base(channel)
- {
- }
- /// <summary>Creates a new client for RouteGuide that uses a custom <c>CallInvoker</c>.</summary>
- /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
- public RouteGuideClient(grpc::CallInvoker callInvoker) : base(callInvoker)
- {
- }
- /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
- protected RouteGuideClient() : base()
- {
- }
- /// <summary>Protected constructor to allow creation of configured clients.</summary>
- /// <param name="configuration">The client configuration.</param>
- protected RouteGuideClient(ClientBaseConfiguration configuration) : base(configuration)
- {
- }
-
- /// <summary>
- /// A simple RPC.
- ///
- /// Obtains the feature at a given position.
- ///
- /// A feature with an empty name is returned if there's no feature at the given
- /// position.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return GetFeature(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// A simple RPC.
- ///
- /// Obtains the feature at a given position.
- ///
- /// A feature with an empty name is returned if there's no feature at the given
- /// position.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The response received from the server.</returns>
- public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::CallOptions options)
- {
- return CallInvoker.BlockingUnaryCall(__Method_GetFeature, null, options, request);
- }
- /// <summary>
- /// A simple RPC.
- ///
- /// Obtains the feature at a given position.
- ///
- /// A feature with an empty name is returned if there's no feature at the given
- /// position.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Routeguide.Feature> GetFeatureAsync(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return GetFeatureAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// A simple RPC.
- ///
- /// Obtains the feature at a given position.
- ///
- /// A feature with an empty name is returned if there's no feature at the given
- /// position.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncUnaryCall<global::Routeguide.Feature> GetFeatureAsync(global::Routeguide.Point request, grpc::CallOptions options)
- {
- return CallInvoker.AsyncUnaryCall(__Method_GetFeature, null, options, request);
- }
- /// <summary>
- /// A server-to-client streaming RPC.
- ///
- /// Obtains the Features available within the given Rectangle. Results are
- /// streamed rather than returned at once (e.g. in a response message with a
- /// repeated field), as the rectangle may cover a large area and contain a
- /// huge number of features.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncServerStreamingCall<global::Routeguide.Feature> ListFeatures(global::Routeguide.Rectangle request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return ListFeatures(request, new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// A server-to-client streaming RPC.
- ///
- /// Obtains the Features available within the given Rectangle. Results are
- /// streamed rather than returned at once (e.g. in a response message with a
- /// repeated field), as the rectangle may cover a large area and contain a
- /// huge number of features.
- /// </summary>
- /// <param name="request">The request to send to the server.</param>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncServerStreamingCall<global::Routeguide.Feature> ListFeatures(global::Routeguide.Rectangle request, grpc::CallOptions options)
- {
- return CallInvoker.AsyncServerStreamingCall(__Method_ListFeatures, null, options, request);
- }
- /// <summary>
- /// A client-to-server streaming RPC.
- ///
- /// Accepts a stream of Points on a route being traversed, returning a
- /// RouteSummary when traversal is completed.
- /// </summary>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncClientStreamingCall<global::Routeguide.Point, global::Routeguide.RouteSummary> RecordRoute(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return RecordRoute(new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// A client-to-server streaming RPC.
- ///
- /// Accepts a stream of Points on a route being traversed, returning a
- /// RouteSummary when traversal is completed.
- /// </summary>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncClientStreamingCall<global::Routeguide.Point, global::Routeguide.RouteSummary> RecordRoute(grpc::CallOptions options)
- {
- return CallInvoker.AsyncClientStreamingCall(__Method_RecordRoute, null, options);
- }
- /// <summary>
- /// A Bidirectional streaming RPC.
- ///
- /// Accepts a stream of RouteNotes sent while a route is being traversed,
- /// while receiving other RouteNotes (e.g. from other users).
- /// </summary>
- /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
- /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
- /// <param name="cancellationToken">An optional token for canceling the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncDuplexStreamingCall<global::Routeguide.RouteNote, global::Routeguide.RouteNote> RouteChat(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
- {
- return RouteChat(new grpc::CallOptions(headers, deadline, cancellationToken));
- }
- /// <summary>
- /// A Bidirectional streaming RPC.
- ///
- /// Accepts a stream of RouteNotes sent while a route is being traversed,
- /// while receiving other RouteNotes (e.g. from other users).
- /// </summary>
- /// <param name="options">The options for the call.</param>
- /// <returns>The call object.</returns>
- public virtual grpc::AsyncDuplexStreamingCall<global::Routeguide.RouteNote, global::Routeguide.RouteNote> RouteChat(grpc::CallOptions options)
- {
- return CallInvoker.AsyncDuplexStreamingCall(__Method_RouteChat, null, options);
- }
- /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
- protected override RouteGuideClient NewInstance(ClientBaseConfiguration configuration)
- {
- return new RouteGuideClient(configuration);
- }
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
- public static grpc::ServerServiceDefinition BindService(RouteGuideBase serviceImpl)
- {
- return grpc::ServerServiceDefinition.CreateBuilder()
- .AddMethod(__Method_GetFeature, serviceImpl.GetFeature)
- .AddMethod(__Method_ListFeatures, serviceImpl.ListFeatures)
- .AddMethod(__Method_RecordRoute, serviceImpl.RecordRoute)
- .AddMethod(__Method_RouteChat, serviceImpl.RouteChat).Build();
- }
-
- }
-}
-#endregion
diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs
index f9af190888..96bd8ca09b 100644
--- a/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs
+++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs
@@ -108,6 +108,7 @@ namespace Routeguide
return features;
}
+#pragma warning disable 0649 // Suppresses "Field 'x' is never assigned to".
private class JsonFeature
{
public string name;
@@ -119,5 +120,6 @@ namespace Routeguide
public int longitude;
public int latitude;
}
+#pragma warning restore 0649
}
}
diff --git a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
index c6dadf082b..b773dd0923 100644
--- a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
+++ b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
@@ -1,12 +1,8 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>RouteGuideClient</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>RouteGuideClient</AssemblyName>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
- <PackageId>RouteGuideClient</PackageId>
</PropertyGroup>
<ItemGroup>
diff --git a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
index 005c87ca0c..b773dd0923 100644
--- a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
+++ b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
@@ -1,12 +1,8 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <AssemblyTitle>RouteGuideServer</AssemblyTitle>
- <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
- <DebugType>portable</DebugType>
- <AssemblyName>RouteGuideServer</AssemblyName>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
- <PackageId>RouteGuideServer</PackageId>
</PropertyGroup>
<ItemGroup>
diff --git a/examples/csharp/RouteGuide/generate_protos.bat b/examples/csharp/RouteGuide/generate_protos.bat
deleted file mode 100644
index f3a4382cf1..0000000000
--- a/examples/csharp/RouteGuide/generate_protos.bat
+++ /dev/null
@@ -1,28 +0,0 @@
-@rem Copyright 2016 gRPC authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-
-@rem Generate the C# code for .proto files
-
-setlocal
-
-@rem enter this directory
-cd /d %~dp0
-
-@rem packages will be available in nuget cache directory once the project is built or after "dotnet restore"
-set PROTOC=%UserProfile%\.nuget\packages\Google.Protobuf.Tools\3.6.1\tools\windows_x64\protoc.exe
-set PLUGIN=%UserProfile%\.nuget\packages\Grpc.Tools\1.14.1\tools\windows_x64\grpc_csharp_plugin.exe
-
-%PROTOC% -I../../protos --csharp_out RouteGuide ../../protos/route_guide.proto --grpc_out RouteGuide --plugin=protoc-gen-grpc=%PLUGIN%
-
-endlocal
diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
index df5c40cda2..e067e82b3d 100644
--- a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
+++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
@@ -132,6 +132,8 @@
TargetAttributes = {
5E36905F1B2A23800040F884 = {
CreatedOnToolsVersion = 6.2;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Manual;
};
};
};
@@ -321,9 +323,12 @@
baseConfigurationReference = DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
INFOPLIST_FILE = HelloWorld/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "Google Development";
};
name = Debug;
};
@@ -332,9 +337,12 @@
baseConfigurationReference = 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = HelloWorld/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Release;
};
diff --git a/examples/objective-c/helloworld_macos/HelloWorld.podspec b/examples/objective-c/helloworld_macos/HelloWorld.podspec
new file mode 100644
index 0000000000..fc671ef4da
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld.podspec
@@ -0,0 +1,66 @@
+Pod::Spec.new do |s|
+ s.name = "HelloWorld"
+ s.version = "0.0.1"
+ s.license = "Apache License, Version 2.0"
+ s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+ s.homepage = "https://grpc.io/"
+ s.summary = "HelloWorld example"
+ s.source = { :git => 'https://github.com/grpc/grpc.git' }
+
+ s.ios.deployment_target = "7.1"
+ s.osx.deployment_target = "10.9"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"
+
+ # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
+ pods_root = 'Pods'
+
+ # Path where Cocoapods downloads protoc and the gRPC plugin.
+ protoc_dir = "#{pods_root}/!ProtoCompiler"
+ protoc = "#{protoc_dir}/protoc"
+ plugin = "#{pods_root}/!ProtoCompiler-gRPCPlugin/grpc_objective_c_plugin"
+
+ # Directory where the generated files will be placed.
+ dir = "#{pods_root}/#{s.name}"
+
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ #{protoc} \
+ --plugin=protoc-gen-grpc=#{plugin} \
+ --objc_out=#{dir} \
+ --grpc_out=#{dir} \
+ -I #{src} \
+ -I #{protoc_dir} \
+ #{src}/helloworld.proto
+ CMD
+
+ # Files generated by protoc
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ # The generated files depend on the protobuf runtime.
+ ms.dependency "Protobuf"
+ end
+
+ # Files generated by the gRPC plugin
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ # The generated files depend on the gRPC runtime, and on the files generated by protoc.
+ ss.dependency "gRPC-ProtoRPC"
+ ss.dependency "#{s.name}/Messages"
+ end
+
+ s.pod_target_xcconfig = {
+ # This is needed by all pods that depend on Protobuf:
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+ # This is needed by all pods that depend on gRPC-RxLibrary:
+ 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+ }
+end
diff --git a/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..06f06290d5
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,399 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 5EF711A4215174880077496F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A3215174880077496F /* AppDelegate.m */; };
+ 5EF711A7215174880077496F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A6215174880077496F /* ViewController.m */; };
+ 5EF711A9215174890077496F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711A8215174890077496F /* Assets.xcassets */; };
+ 5EF711AC215174890077496F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711AA215174890077496F /* Main.storyboard */; };
+ 5EF711AF215174890077496F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711AE215174890077496F /* main.m */; };
+ 827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
+ 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5EF7119F215174870077496F /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5EF711A2215174880077496F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 5EF711A3215174880077496F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 5EF711A5215174880077496F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ 5EF711A6215174880077496F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ 5EF711A8215174890077496F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ 5EF711AB215174890077496F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 5EF711AD215174890077496F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 5EF711AE215174890077496F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 5EF711B0215174890077496F /* HelloWorld.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HelloWorld.entitlements; sourceTree = "<group>"; };
+ CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5EF7119C215174870077496F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 5EF71196215174870077496F = {
+ isa = PBXGroup;
+ children = (
+ 5EF711AE215174890077496F /* main.m */,
+ 5EF711A1215174870077496F /* HelloWorld */,
+ 5EF711A0215174870077496F /* Products */,
+ 8D3EFBB796129582177142C4 /* Pods */,
+ A986548CB5622AF6CC3ECCCE /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 5EF711A0215174870077496F /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5EF7119F215174870077496F /* HelloWorld.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 5EF711A1215174870077496F /* HelloWorld */ = {
+ isa = PBXGroup;
+ children = (
+ 5EF711A2215174880077496F /* AppDelegate.h */,
+ 5EF711A3215174880077496F /* AppDelegate.m */,
+ 5EF711A5215174880077496F /* ViewController.h */,
+ 5EF711A6215174880077496F /* ViewController.m */,
+ 5EF711A8215174890077496F /* Assets.xcassets */,
+ 5EF711AA215174890077496F /* Main.storyboard */,
+ 5EF711AD215174890077496F /* Info.plist */,
+ 5EF711B0215174890077496F /* HelloWorld.entitlements */,
+ );
+ path = HelloWorld;
+ sourceTree = "<group>";
+ };
+ 8D3EFBB796129582177142C4 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */,
+ 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ A986548CB5622AF6CC3ECCCE /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 5EF7119E215174870077496F /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ 3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */,
+ 5EF7119B215174870077496F /* Sources */,
+ 5EF7119C215174870077496F /* Frameworks */,
+ 5EF7119D215174870077496F /* Resources */,
+ DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = HelloWorld;
+ productReference = 5EF7119F215174870077496F /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 5EF71197215174870077496F /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0930;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 5EF7119E215174870077496F = {
+ CreatedOnToolsVersion = 9.3;
+ SystemCapabilities = {
+ com.apple.Sandbox = {
+ enabled = 0;
+ };
+ };
+ };
+ };
+ };
+ buildConfigurationList = 5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 5EF71196215174870077496F;
+ productRefGroup = 5EF711A0215174870077496F /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 5EF7119E215174870077496F /* HelloWorld */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 5EF7119D215174870077496F /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5EF711A9215174890077496F /* Assets.xcassets in Resources */,
+ 5EF711AC215174890077496F /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-HelloWorld-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 5EF7119B215174870077496F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5EF711A7215174880077496F /* ViewController.m in Sources */,
+ 5EF711AF215174890077496F /* main.m in Sources */,
+ 5EF711A4215174880077496F /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 5EF711AA215174890077496F /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 5EF711AB215174890077496F /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 5EF711B1215174890077496F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ 5EF711B2215174890077496F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ 5EF711B4215174890077496F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 5EF711B5215174890077496F /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5EF711B1215174890077496F /* Debug */,
+ 5EF711B2215174890077496F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5EF711B4215174890077496F /* Debug */,
+ 5EF711B5215174890077496F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 5EF71197215174870077496F /* Project object */;
+}
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h
new file mode 100644
index 0000000000..1b88e35d22
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+
+
+@end
+
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m
new file mode 100644
index 0000000000..7da5e1171b
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ // Insert code here to initialize your application
+}
+
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification {
+ // Insert code here to tear down your application
+}
+
+
+@end
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..2db2b1c7c6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..da4a164c91
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard b/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..3ed4144fba
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard
@@ -0,0 +1,717 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
+ </dependencies>
+ <scenes>
+ <!--Application-->
+ <scene sceneID="JPo-4y-FX3">
+ <objects>
+ <application id="hnw-xV-0zn" sceneMemberID="viewController">
+ <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
+ <items>
+ <menuItem title="HelloWorld" id="1Xt-HY-uBw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="HelloWorld" systemMenu="apple" id="uQy-DD-JDr">
+ <items>
+ <menuItem title="About HelloWorld" id="5kV-Vb-QxS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
+ <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
+ <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
+ <menuItem title="Services" id="NMo-om-nkz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
+ <menuItem title="Hide HelloWorld" keyEquivalent="h" id="Olw-nP-bQN">
+ <connections>
+ <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="Kd2-mp-pUS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
+ <menuItem title="Quit HelloWorld" keyEquivalent="q" id="4sb-4s-VLi">
+ <connections>
+ <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" id="dMs-cI-mzQ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="File" id="bib-Uj-vzu">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
+ <connections>
+ <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
+ <connections>
+ <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="tXI-mr-wws">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
+ <items>
+ <menuItem title="Clear Menu" id="vNY-rz-j42">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
+ <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
+ <connections>
+ <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
+ <connections>
+ <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
+ <connections>
+ <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
+ <connections>
+ <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
+ <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
+ <connections>
+ <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" id="5QF-Oa-p0T">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Edit" id="W48-6f-4Dl">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
+ <connections>
+ <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
+ <connections>
+ <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
+ <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
+ <connections>
+ <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
+ <connections>
+ <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
+ <connections>
+ <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="pa3-QI-u2k">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
+ <connections>
+ <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
+ <menuItem title="Find" id="4EN-yA-p0u">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Find" id="1b7-l0-nxx">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
+ <items>
+ <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
+ <connections>
+ <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
+ <connections>
+ <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
+ <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="9ic-FL-obx">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
+ <items>
+ <menuItem title="Show Substitutions" id="z6F-FW-3nz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
+ <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" id="hQb-2v-fYv">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Dashes" id="rgM-f4-ycn">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" id="cwL-P1-jid">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Data Detectors" id="tRr-pd-1PS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Text Replacement" id="HFQ-gK-NFA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Transformations" id="2oI-Rn-ZJC">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
+ <items>
+ <menuItem title="Make Upper Case" id="vmV-6d-7jI">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Make Lower Case" id="d9M-CD-aMd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Capitalize" id="UEZ-Bs-lqG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="xrE-MZ-jX0">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
+ <items>
+ <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" id="jxT-CU-nIS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Format" id="GEO-Iw-cKr">
+ <items>
+ <menuItem title="Font" id="Gi5-1S-RQB">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
+ <connections>
+ <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
+ <connections>
+ <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
+ <connections>
+ <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
+ <connections>
+ <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
+ <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
+ <connections>
+ <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
+ <connections>
+ <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
+ <menuItem title="Kern" id="jBQ-r6-VK2">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Kern" id="tlD-Oa-oAM">
+ <items>
+ <menuItem title="Use Default" id="GUa-eO-cwY">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="cDB-IK-hbR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Tighten" id="46P-cB-AYj">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Loosen" id="ogc-rX-tC1">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Ligatures" id="o6e-r0-MWq">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
+ <items>
+ <menuItem title="Use Default" id="agt-UL-0e3">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="J7y-lM-qPV">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use All" id="xQD-1f-W4t">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Baseline" id="OaQ-X3-Vso">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Baseline" id="ijk-EB-dga">
+ <items>
+ <menuItem title="Use Default" id="3Om-Ey-2VK">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Superscript" id="Rqc-34-cIF">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Subscript" id="I0S-gh-46l">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Raise" id="2h7-ER-AoG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Lower" id="1tx-W0-xDw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
+ <connections>
+ <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
+ <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Text" id="Fal-I4-PZk">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Text" id="d9c-me-L2H">
+ <items>
+ <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
+ <connections>
+ <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
+ <connections>
+ <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Justify" id="J5U-5w-g23">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
+ <connections>
+ <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
+ <menuItem title="Writing Direction" id="H1b-Si-o9J">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
+ <items>
+ <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="YGs-j5-SAR">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
+ </connections>
+ </menuItem>
+ <menuItem id="Lbh-J2-qVU">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
+ </connections>
+ </menuItem>
+ <menuItem id="jFq-tB-4Kx">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
+ <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="Nop-cj-93Q">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
+ </connections>
+ </menuItem>
+ <menuItem id="BgM-ve-c93">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
+ </connections>
+ </menuItem>
+ <menuItem id="RB4-Sm-HuC">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
+ <menuItem title="Show Ruler" id="vLm-3I-IUL">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" id="H8h-7b-M4v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="View" id="HyV-fh-RgO">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
+ <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" id="aUF-d1-5bR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
+ <connections>
+ <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="R4o-n2-Eq4">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
+ <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" id="wpr-3q-Mcd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
+ <items>
+ <menuItem title="HelloWorld Help" keyEquivalent="?" id="FKE-Sm-Kum">
+ <connections>
+ <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <connections>
+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
+ </connections>
+ </application>
+ <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider=""/>
+ <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
+ <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="0.0"/>
+ </scene>
+ <!--Window Controller-->
+ <scene sceneID="R2V-B0-nI4">
+ <objects>
+ <windowController id="B8D-0N-5wS" sceneMemberID="viewController">
+ <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="196" y="240" width="480" height="270"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
+ <connections>
+ <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
+ </connections>
+ </window>
+ <connections>
+ <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
+ </connections>
+ </windowController>
+ <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="250"/>
+ </scene>
+ <!--View Controller-->
+ <scene sceneID="hIz-AP-VOD">
+ <objects>
+ <viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </view>
+ </viewController>
+ <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="655"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements b/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements
new file mode 100644
index 0000000000..0c67376eba
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Info.plist b/examples/objective-c/helloworld_macos/HelloWorld/Info.plist
new file mode 100644
index 0000000000..f7bfdac9d6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2018 gRPC. All rights reserved.</string>
+ <key>NSMainStoryboardFile</key>
+ <string>Main</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h
new file mode 100644
index 0000000000..ff620dc426
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ViewController : NSViewController
+
+
+@end
+
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m
new file mode 100644
index 0000000000..fc9e95f9a6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import "ViewController.h"
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Do any additional setup after loading the view.
+}
+
+
+- (void)setRepresentedObject:(id)representedObject {
+ [super setRepresentedObject:representedObject];
+
+ // Update the view, if already loaded.
+}
+
+
+@end
diff --git a/examples/objective-c/helloworld_macos/Podfile b/examples/objective-c/helloworld_macos/Podfile
new file mode 100644
index 0000000000..bf1488cba6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/Podfile
@@ -0,0 +1,9 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :macos, '10.9'
+
+install! 'cocoapods', :deterministic_uuids => false
+
+target 'HelloWorld' do
+ # Depend on the generated HelloWorld library.
+ pod 'HelloWorld', :path => '.'
+end
diff --git a/examples/objective-c/helloworld_macos/README.md b/examples/objective-c/helloworld_macos/README.md
new file mode 100644
index 0000000000..295701b5e6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/README.md
@@ -0,0 +1,6 @@
+# gRPC Objective-C Mac OS Hello World Example
+
+A hello world example app on Mac OS. Note that Mac OS is not a first class supported platform of gRPC
+Objective-C library. This example is only for reference.
+
+Refer to [Hello World Example](../helloworld) for instructions on installation and running.
diff --git a/examples/objective-c/helloworld_macos/main.m b/examples/objective-c/helloworld_macos/main.m
new file mode 100644
index 0000000000..2a98ec4966
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/main.m
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import <GRPCClient/GRPCCall+ChannelArg.h>
+#import <GRPCClient/GRPCCall+Tests.h>
+#import <HelloWorld/Helloworld.pbrpc.h>
+
+static NSString * const kHostAddress = @"localhost:50051";
+
+int main(int argc, const char * argv[]) {
+ @autoreleasepool {
+ [GRPCCall useInsecureConnectionsForHost:kHostAddress];
+ [GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
+
+ HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
+
+ HLWHelloRequest *request = [HLWHelloRequest message];
+ request.name = @"Objective-C";
+
+ [client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
+ NSLog(@"%@", response.message);
+ }];
+ }
+
+ return NSApplicationMain(argc, argv);
+}
diff --git a/examples/python/helloworld/greeter_client.py b/examples/python/helloworld/greeter_client.py
index 24b49ac233..ee2032a9e6 100644
--- a/examples/python/helloworld/greeter_client.py
+++ b/examples/python/helloworld/greeter_client.py
@@ -14,6 +14,7 @@
"""The Python implementation of the GRPC helloworld.Greeter client."""
from __future__ import print_function
+import logging
import grpc
@@ -32,4 +33,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/helloworld/greeter_client_with_options.py b/examples/python/helloworld/greeter_client_with_options.py
index 7eda8c9066..d15871b519 100644
--- a/examples/python/helloworld/greeter_client_with_options.py
+++ b/examples/python/helloworld/greeter_client_with_options.py
@@ -14,6 +14,7 @@
"""The Python implementation of the GRPC helloworld.Greeter client with channel options and call timeout parameters."""
from __future__ import print_function
+import logging
import grpc
@@ -41,4 +42,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py
index c355662ef8..e3b4f2c1ff 100644
--- a/examples/python/helloworld/greeter_server.py
+++ b/examples/python/helloworld/greeter_server.py
@@ -15,6 +15,7 @@
from concurrent import futures
import time
+import logging
import grpc
@@ -43,4 +44,5 @@ def serve():
if __name__ == '__main__':
+ logging.basicConfig()
serve()
diff --git a/examples/python/helloworld/greeter_server_with_reflection.py b/examples/python/helloworld/greeter_server_with_reflection.py
index 5ba8782dfc..5acedbcb71 100644
--- a/examples/python/helloworld/greeter_server_with_reflection.py
+++ b/examples/python/helloworld/greeter_server_with_reflection.py
@@ -15,6 +15,7 @@
from concurrent import futures
import time
+import logging
import grpc
from grpc_reflection.v1alpha import reflection
@@ -49,4 +50,5 @@ def serve():
if __name__ == '__main__':
+ logging.basicConfig()
serve()
diff --git a/examples/python/interceptors/default_value/greeter_client.py b/examples/python/interceptors/default_value/greeter_client.py
index da21ac68ec..25834c2bbd 100644
--- a/examples/python/interceptors/default_value/greeter_client.py
+++ b/examples/python/interceptors/default_value/greeter_client.py
@@ -14,6 +14,7 @@
"""The Python implementation of the gRPC helloworld.Greeter client."""
from __future__ import print_function
+import logging
import grpc
@@ -39,4 +40,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/interceptors/headers/greeter_client.py b/examples/python/interceptors/headers/greeter_client.py
index 6a09a3b9c5..712539850d 100644
--- a/examples/python/interceptors/headers/greeter_client.py
+++ b/examples/python/interceptors/headers/greeter_client.py
@@ -14,6 +14,7 @@
"""The Python implementation of the GRPC helloworld.Greeter client."""
from __future__ import print_function
+import logging
import grpc
@@ -37,4 +38,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/interceptors/headers/greeter_server.py b/examples/python/interceptors/headers/greeter_server.py
index 01968609b5..6b0f4058bc 100644
--- a/examples/python/interceptors/headers/greeter_server.py
+++ b/examples/python/interceptors/headers/greeter_server.py
@@ -15,6 +15,7 @@
from concurrent import futures
import time
+import logging
import grpc
@@ -49,4 +50,5 @@ def serve():
if __name__ == '__main__':
+ logging.basicConfig()
serve()
diff --git a/examples/python/multiplex/multiplex_client.py b/examples/python/multiplex/multiplex_client.py
index 19d39ce66e..155f85c4b0 100644
--- a/examples/python/multiplex/multiplex_client.py
+++ b/examples/python/multiplex/multiplex_client.py
@@ -17,6 +17,7 @@ from __future__ import print_function
import random
import time
+import logging
import grpc
@@ -126,4 +127,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/multiplex/multiplex_server.py b/examples/python/multiplex/multiplex_server.py
index 70dec3c939..c01824b3a9 100644
--- a/examples/python/multiplex/multiplex_server.py
+++ b/examples/python/multiplex/multiplex_server.py
@@ -16,6 +16,7 @@
from concurrent import futures
import time
import math
+import logging
import grpc
@@ -136,4 +137,5 @@ def serve():
if __name__ == '__main__':
+ logging.basicConfig()
serve()
diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py
index b4ff3239ba..dc93fb4437 100644
--- a/examples/python/route_guide/route_guide_client.py
+++ b/examples/python/route_guide/route_guide_client.py
@@ -16,6 +16,7 @@
from __future__ import print_function
import random
+import logging
import grpc
@@ -116,4 +117,5 @@ def run():
if __name__ == '__main__':
+ logging.basicConfig()
run()
diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py
index 1969fdd378..e00cb69908 100644
--- a/examples/python/route_guide/route_guide_server.py
+++ b/examples/python/route_guide/route_guide_server.py
@@ -16,6 +16,7 @@
from concurrent import futures
import time
import math
+import logging
import grpc
@@ -126,4 +127,5 @@ def serve():
if __name__ == '__main__':
+ logging.basicConfig()
serve()
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 187551da87..e939bead1b 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -23,15 +23,15 @@
Pod::Spec.new do |s|
s.name = 'gRPC-C++'
# TODO (mxyan): use version that match gRPC version when pod is stabilized
- # version = '1.17.0-dev'
- version = '0.0.3'
+ # version = '1.18.0-dev'
+ version = '0.0.6-dev'
s.version = version
s.summary = 'gRPC C++ library'
s.homepage = 'https://grpc.io'
s.license = 'Apache License, Version 2.0'
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
- grpc_version = '1.17.0-dev'
+ grpc_version = '1.18.0-dev'
s.source = {
:git => 'https://github.com/grpc/grpc.git',
@@ -69,6 +69,9 @@ Pod::Spec.new do |s|
s.default_subspecs = 'Interface', 'Implementation'
+ # Certificates, to be able to establish TLS connections:
+ s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
+
s.header_mappings_dir = 'include/grpcpp'
s.subspec 'Interface' do |ss|
@@ -115,6 +118,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/config.h',
'include/grpcpp/support/proto_buffer_reader.h',
'include/grpcpp/support/proto_buffer_writer.h',
+ 'include/grpcpp/support/server_callback.h',
'include/grpcpp/support/slice.h',
'include/grpcpp/support/status.h',
'include/grpcpp/support/status_code_enum.h',
@@ -128,6 +132,8 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/byte_buffer.h',
'include/grpcpp/impl/codegen/call.h',
'include/grpcpp/impl/codegen/call_hook.h',
+ 'include/grpcpp/impl/codegen/call_op_set.h',
+ 'include/grpcpp/impl/codegen/call_op_set_interface.h',
'include/grpcpp/impl/codegen/callback_common.h',
'include/grpcpp/impl/codegen/channel_interface.h',
'include/grpcpp/impl/codegen/client_callback.h',
@@ -140,14 +146,18 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/core_codegen_interface.h',
'include/grpcpp/impl/codegen/create_auth_context.h',
'include/grpcpp/impl/codegen/grpc_library.h',
+ 'include/grpcpp/impl/codegen/intercepted_channel.h',
'include/grpcpp/impl/codegen/interceptor.h',
+ 'include/grpcpp/impl/codegen/interceptor_common.h',
'include/grpcpp/impl/codegen/metadata_map.h',
'include/grpcpp/impl/codegen/method_handler_impl.h',
'include/grpcpp/impl/codegen/rpc_method.h',
'include/grpcpp/impl/codegen/rpc_service_method.h',
'include/grpcpp/impl/codegen/security/auth_context.h',
'include/grpcpp/impl/codegen/serialization_traits.h',
+ 'include/grpcpp/impl/codegen/server_callback.h',
'include/grpcpp/impl/codegen/server_context.h',
+ 'include/grpcpp/impl/codegen/server_interceptor.h',
'include/grpcpp/impl/codegen/server_interface.h',
'include/grpcpp/impl/codegen/service_type.h',
'include/grpcpp/impl/codegen/slice.h',
@@ -185,6 +195,7 @@ Pod::Spec.new do |s|
'src/cpp/server/secure_server_credentials.cc',
'src/cpp/client/channel_cc.cc',
'src/cpp/client/client_context.cc',
+ 'src/cpp/client/client_interceptor.cc',
'src/cpp/client/create_channel.cc',
'src/cpp/client/create_channel_internal.cc',
'src/cpp/client/create_channel_posix.cc',
@@ -245,6 +256,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+ 'src/core/ext/transport/chttp2/transport/context_list.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
@@ -303,7 +315,7 @@ Pod::Spec.new do |s|
'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
'src/core/tsi/alts/frame_protector/frame_handler.h',
'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
@@ -336,20 +348,18 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
- 'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
- 'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',
- 'src/core/tsi/alts_transport_security.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -395,6 +405,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/call_combiner.h',
'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/combiner.h',
+ 'src/core/lib/iomgr/dynamic_annotations.h',
'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
@@ -494,6 +505,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
+ 'src/core/lib/uri/uri_parser.h',
'src/core/lib/debug/trace.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@@ -586,6 +598,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/call_combiner.h',
'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/combiner.h',
+ 'src/core/lib/iomgr/dynamic_annotations.h',
'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
@@ -685,6 +698,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
+ 'src/core/lib/uri/uri_parser.h',
'src/core/lib/debug/trace.h',
'src/core/ext/transport/inproc/inproc_transport.h',
'src/core/ext/filters/client_channel/health/health.pb.h'
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index bbd5d7e961..1d4e1ae35c 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -22,7 +22,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
- version = '1.17.0-dev'
+ version = '1.18.0-dev'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'https://grpc.io'
@@ -254,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+ 'src/core/ext/transport/chttp2/transport/context_list.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
@@ -312,7 +313,7 @@ Pod::Spec.new do |s|
'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
'src/core/tsi/alts/frame_protector/frame_handler.h',
'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
@@ -345,20 +346,18 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
- 'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
- 'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',
- 'src/core/tsi/alts_transport_security.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -404,6 +403,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/call_combiner.h',
'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/combiner.h',
+ 'src/core/lib/iomgr/dynamic_annotations.h',
'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
@@ -503,6 +503,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
+ 'src/core/lib/uri/uri_parser.h',
'src/core/lib/debug/trace.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@@ -674,12 +675,14 @@ Pod::Spec.new do |s|
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc',
'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -746,7 +749,7 @@ Pod::Spec.new do |s|
'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
'src/core/tsi/alts/frame_protector/frame_handler.cc',
'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.cc',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
@@ -785,19 +788,17 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
- 'src/core/tsi/alts_transport_security.cc',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
@@ -873,6 +874,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+ 'src/core/ext/transport/chttp2/transport/context_list.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
@@ -931,7 +933,7 @@ Pod::Spec.new do |s|
'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
'src/core/tsi/alts/frame_protector/frame_handler.h',
'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
@@ -964,20 +966,18 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
- 'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
- 'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',
- 'src/core/tsi/alts_transport_security.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -1023,6 +1023,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/call_combiner.h',
'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/combiner.h',
+ 'src/core/lib/iomgr/dynamic_annotations.h',
'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
@@ -1122,6 +1123,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
+ 'src/core/lib/uri/uri_parser.h',
'src/core/lib/debug/trace.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index 693b873d14..13fe3e0b9c 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
- version = '1.17.0-dev'
+ version = '1.18.0-dev'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'https://grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index fd590023e1..e132ad41b4 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
- version = '1.17.0-dev'
+ version = '1.18.0-dev'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'https://grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index d8aa997e7c..5fbcb6b0b7 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -20,7 +20,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
- version = '1.17.0-dev'
+ version = '1.18.0-dev'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'https://grpc.io'
diff --git a/grpc.def b/grpc.def
index 2379cf17e6..b3466c004d 100644
--- a/grpc.def
+++ b/grpc.def
@@ -75,6 +75,7 @@ EXPORTS
grpc_resource_quota_arg_vtable
grpc_channelz_get_top_channels
grpc_channelz_get_servers
+ grpc_channelz_get_server
grpc_channelz_get_server_sockets
grpc_channelz_get_channel
grpc_channelz_get_subchannel
diff --git a/grpc.gemspec b/grpc.gemspec
index a3924d0d93..92b1e0be68 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -186,6 +186,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h )
+ s.files += %w( src/core/ext/transport/chttp2/transport/context_list.h )
s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h )
@@ -244,7 +245,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h )
s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.h )
s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.h )
- s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.h )
+ s.files += %w( src/core/tsi/alts/handshaker/alts_shared_resource.h )
s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.h )
s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h )
s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h )
@@ -281,20 +282,18 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
- s.files += %w( src/core/ext/filters/client_channel/method_params.h )
s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
s.files += %w( src/core/ext/filters/client_channel/resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_factory.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
+ s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
- s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/filters/client_channel/health/health.pb.h )
- s.files += %w( src/core/tsi/alts_transport_security.h )
s.files += %w( src/core/tsi/fake_transport_security.h )
s.files += %w( src/core/tsi/local_transport_security.h )
s.files += %w( src/core/tsi/ssl/session_cache/ssl_session.h )
@@ -340,6 +339,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/call_combiner.h )
s.files += %w( src/core/lib/iomgr/closure.h )
s.files += %w( src/core/lib/iomgr/combiner.h )
+ s.files += %w( src/core/lib/iomgr/dynamic_annotations.h )
s.files += %w( src/core/lib/iomgr/endpoint.h )
s.files += %w( src/core/lib/iomgr/endpoint_pair.h )
s.files += %w( src/core/lib/iomgr/error.h )
@@ -439,6 +439,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/timeout_encoding.h )
s.files += %w( src/core/lib/transport/transport.h )
s.files += %w( src/core/lib/transport/transport_impl.h )
+ s.files += %w( src/core/lib/uri/uri_parser.h )
s.files += %w( src/core/lib/debug/trace.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
@@ -610,12 +611,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/timeout_encoding.cc )
s.files += %w( src/core/lib/transport/transport.cc )
s.files += %w( src/core/lib/transport/transport_op_string.cc )
+ s.files += %w( src/core/lib/uri/uri_parser.cc )
s.files += %w( src/core/lib/debug/trace.cc )
s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_plugin.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.cc )
+ s.files += %w( src/core/ext/transport/chttp2/transport/context_list.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.cc )
@@ -682,7 +685,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc )
s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.cc )
s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.cc )
- s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.cc )
+ s.files += %w( src/core/tsi/alts/handshaker/alts_shared_resource.cc )
s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc )
s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc )
s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc )
@@ -724,19 +727,17 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc )
- s.files += %w( src/core/ext/filters/client_channel/method_params.cc )
s.files += %w( src/core/ext/filters/client_channel/parse_address.cc )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc )
+ s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc )
- s.files += %w( src/core/ext/filters/client_channel/uri_parser.cc )
s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc )
s.files += %w( src/core/ext/filters/client_channel/health/health.pb.c )
- s.files += %w( src/core/tsi/alts_transport_security.cc )
s.files += %w( src/core/tsi/fake_transport_security.cc )
s.files += %w( src/core/tsi/local_transport_security.cc )
s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 963b8b22b1..564922ff72 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -426,12 +426,14 @@
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc',
'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -498,7 +500,7 @@
'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
'src/core/tsi/alts/frame_protector/frame_handler.cc',
'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.cc',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
@@ -540,19 +542,17 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
- 'src/core/tsi/alts_transport_security.cc',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
@@ -786,6 +786,7 @@
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/filters/client_channel/backup_poller.cc',
'src/core/ext/filters/client_channel/channel_connectivity.cc',
@@ -800,16 +801,15 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
'third_party/nanopb/pb_common.c',
@@ -819,6 +819,7 @@
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -1025,6 +1026,7 @@
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/filters/client_channel/backup_poller.cc',
'src/core/ext/filters/client_channel/channel_connectivity.cc',
@@ -1039,16 +1041,15 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
'third_party/nanopb/pb_common.c',
@@ -1058,6 +1059,7 @@
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -1242,6 +1244,7 @@
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc',
@@ -1249,6 +1252,7 @@
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -1290,16 +1294,15 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
'third_party/nanopb/pb_common.c',
@@ -1386,6 +1389,7 @@
'src/cpp/server/secure_server_credentials.cc',
'src/cpp/client/channel_cc.cc',
'src/cpp/client/client_context.cc',
+ 'src/cpp/client/client_interceptor.cc',
'src/cpp/client/create_channel.cc',
'src/cpp/client/create_channel_internal.cc',
'src/cpp/client/create_channel_posix.cc',
@@ -1493,6 +1497,8 @@
'src/proto/grpc/testing/echo_messages.proto',
'src/proto/grpc/testing/echo.proto',
'src/proto/grpc/testing/duplicate/echo_duplicate.proto',
+ 'src/proto/grpc/testing/simple_messages.proto',
+ 'test/cpp/end2end/test_health_check_service_impl.cc',
'test/cpp/end2end/test_service_impl.cc',
'test/cpp/util/byte_buffer_proto_helper.cc',
'test/cpp/util/channel_trace_proto_helper.cc',
@@ -1516,6 +1522,8 @@
'src/proto/grpc/testing/echo_messages.proto',
'src/proto/grpc/testing/echo.proto',
'src/proto/grpc/testing/duplicate/echo_duplicate.proto',
+ 'src/proto/grpc/testing/simple_messages.proto',
+ 'test/cpp/end2end/test_health_check_service_impl.cc',
'test/cpp/end2end/test_service_impl.cc',
'test/cpp/util/byte_buffer_proto_helper.cc',
'test/cpp/util/string_ref_helper.cc',
@@ -1536,6 +1544,7 @@
'src/cpp/server/insecure_server_credentials.cc',
'src/cpp/client/channel_cc.cc',
'src/cpp/client/client_context.cc',
+ 'src/cpp/client/client_interceptor.cc',
'src/cpp/client/create_channel.cc',
'src/cpp/client/create_channel_internal.cc',
'src/cpp/client/create_channel_posix.cc',
@@ -1756,6 +1765,7 @@
'test/cpp/qps/qps_worker.cc',
'test/cpp/qps/report.cc',
'test/cpp/qps/server_async.cc',
+ 'test/cpp/qps/server_callback.cc',
'test/cpp/qps/server_sync.cc',
'test/cpp/qps/usage_timer.cc',
],
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 514d9ddc4b..d3b74cabab 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -506,6 +506,9 @@ GRPCAPI char* grpc_channelz_get_top_channels(intptr_t start_channel_id);
/* Gets all servers that exist in the process. */
GRPCAPI char* grpc_channelz_get_servers(intptr_t start_server_id);
+/* Returns a single Server, or else a NOT_FOUND code. */
+GRPCAPI char* grpc_channelz_get_server(intptr_t server_id);
+
/* Gets all server sockets that exist in the server. */
GRPCAPI char* grpc_channelz_get_server_sockets(intptr_t server_id,
intptr_t start_socket_id);
diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h
index c0010a3469..728c3d5412 100644
--- a/include/grpc/impl/codegen/atm_gcc_sync.h
+++ b/include/grpc/impl/codegen/atm_gcc_sync.h
@@ -26,6 +26,8 @@
typedef intptr_t gpr_atm;
#define GPR_ATM_MAX INTPTR_MAX
#define GPR_ATM_MIN INTPTR_MIN
+#define GPR_ATM_INC_CAS_THEN(blah) blah
+#define GPR_ATM_INC_ADD_THEN(blah) blah
#define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory")
diff --git a/include/grpc/impl/codegen/atm_windows.h b/include/grpc/impl/codegen/atm_windows.h
index f6b27e5df7..c016b90095 100644
--- a/include/grpc/impl/codegen/atm_windows.h
+++ b/include/grpc/impl/codegen/atm_windows.h
@@ -25,6 +25,8 @@
typedef intptr_t gpr_atm;
#define GPR_ATM_MAX INTPTR_MAX
#define GPR_ATM_MIN INTPTR_MIN
+#define GPR_ATM_INC_CAS_THEN(blah) blah
+#define GPR_ATM_INC_ADD_THEN(blah) blah
#define gpr_atm_full_barrier MemoryBarrier
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 402e490e34..610548b5f3 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -293,7 +293,7 @@ typedef struct {
"grpc.max_channel_trace_event_memory_per_node"
/** If non-zero, gRPC library will track stats and information at at per channel
* level. Disabling channelz naturally disables channel tracing. The default
- * is for channelz to be disabled. */
+ * is for channelz to be enabled. */
#define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz"
/** If non-zero, Cronet transport will coalesce packets to fewer frames
* when possible. */
@@ -350,6 +350,11 @@ typedef struct {
/** If set, inhibits health checking (which may be enabled via the
* service config.) */
#define GRPC_ARG_INHIBIT_HEALTH_CHECKING "grpc.inhibit_health_checking"
+/** If set, determines the number of milliseconds that the c-ares based
+ * DNS resolver will wait on queries before cancelling them. The default value
+ * is 10000. Setting this to "0" will disable c-ares query timeouts
+ * entirely. */
+#define GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS "grpc.dns_ares_query_timeout"
/** gRPC Objective-C channel pooling domain string. */
#define GRPC_ARG_CHANNEL_POOL_DOMAIN "grpc.channel_pooling_domain"
/** gRPC Objective-C channel pooling id. */
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index b2028a6305..031c0c36ae 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -526,6 +526,15 @@ typedef unsigned __int64 uint64_t;
#endif /* GPR_ATTRIBUTE_NO_TSAN (2) */
#endif /* GPR_ATTRIBUTE_NO_TSAN (1) */
+/* GRPC_TSAN_ENABLED will be defined, when compiled with thread sanitizer. */
+#if defined(__SANITIZE_THREAD__)
+#define GRPC_TSAN_ENABLED
+#elif defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#define GRPC_TSAN_ENABLED
+#endif
+#endif
+
/* GRPC_ALLOW_EXCEPTIONS should be 0 or 1 if exceptions are allowed or not */
#ifndef GRPC_ALLOW_EXCEPTIONS
/* If not already set, set to 1 on Windows (style guide standard) but to
diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h
index b7c9e354de..ee83396069 100644
--- a/include/grpcpp/channel.h
+++ b/include/grpcpp/channel.h
@@ -20,6 +20,7 @@
#define GRPCPP_CHANNEL_H
#include <memory>
+#include <mutex>
#include <grpc/grpc.h>
#include <grpcpp/impl/call.h>
@@ -64,12 +65,13 @@ class Channel final : public ChannelInterface,
friend void experimental::ChannelResetConnectionBackoff(Channel* channel);
friend std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
+ friend class internal::InterceptedChannel;
Channel(const grpc::string& host, grpc_channel* c_channel,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
internal::Call CreateCall(const internal::RpcMethod& method,
@@ -87,6 +89,10 @@ class Channel final : public ChannelInterface,
CompletionQueue* CallbackCQ() override;
+ internal::Call CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context, CompletionQueue* cq,
+ size_t interceptor_pos) override;
+
const grpc::string host_;
grpc_channel* const c_channel_; // owned
diff --git a/include/grpcpp/create_channel.h b/include/grpcpp/create_channel.h
index 43188d09e7..e8a2a70581 100644
--- a/include/grpcpp/create_channel.h
+++ b/include/grpcpp/create_channel.h
@@ -70,8 +70,8 @@ std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace experimental
} // namespace grpc
diff --git a/include/grpcpp/generic/generic_stub.h b/include/grpcpp/generic/generic_stub.h
index d509d9a520..eb014184e4 100644
--- a/include/grpcpp/generic/generic_stub.h
+++ b/include/grpcpp/generic/generic_stub.h
@@ -24,6 +24,7 @@
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/byte_buffer.h>
+#include <grpcpp/support/client_callback.h>
#include <grpcpp/support/status.h>
namespace grpc {
@@ -76,6 +77,10 @@ class GenericStub final {
const ByteBuffer* request, ByteBuffer* response,
std::function<void(Status)> on_completion);
+ void PrepareBidiStreamingCall(
+ ClientContext* context, const grpc::string& method,
+ experimental::ClientBidiReactor<ByteBuffer, ByteBuffer>* reactor);
+
private:
GenericStub* stub_;
};
diff --git a/include/grpcpp/health_check_service_interface.h b/include/grpcpp/health_check_service_interface.h
index b45a699bda..dfd4c3983a 100644
--- a/include/grpcpp/health_check_service_interface.h
+++ b/include/grpcpp/health_check_service_interface.h
@@ -37,6 +37,10 @@ class HealthCheckServiceInterface {
bool serving) = 0;
/// Apply to all registered service names.
virtual void SetServingStatus(bool serving) = 0;
+
+ /// Set all registered service names to not serving and prevent future
+ /// state changes.
+ virtual void Shutdown() {}
};
/// Enable/disable the default health checking service. This applies to all C++
diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h
index 6e58fd0eef..bfb2df4f23 100644
--- a/include/grpcpp/impl/codegen/async_stream.h
+++ b/include/grpcpp/impl/codegen/async_stream.h
@@ -276,7 +276,7 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
}
void StartCallInternal(void* tag) {
- init_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ init_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
init_ops_.set_output_tag(tag);
call_.PerformOps(&init_ops_);
@@ -441,7 +441,7 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
}
void StartCallInternal(void* tag) {
- write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
// if corked bit is set in context, we just keep the initial metadata
// buffered up to coalesce with later message send. No op is performed.
@@ -612,7 +612,7 @@ class ClientAsyncReaderWriter final
}
void StartCallInternal(void* tag) {
- write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
// if corked bit is set in context, we just keep the initial metadata
// buffered up to coalesce with later message send. No op is performed.
@@ -710,7 +710,7 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -739,7 +739,7 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
void Finish(const W& msg, const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
@@ -748,10 +748,10 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
}
// The response is dropped if the status is not OK.
if (status.ok()) {
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_ops_.SendMessage(msg));
} else {
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_ops_);
}
@@ -769,14 +769,14 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
GPR_CODEGEN_ASSERT(!status.ok());
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -859,7 +859,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -904,7 +904,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
- write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
@@ -922,7 +922,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -932,7 +932,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
- ops->SendInitialMetadata(ctx_->initial_metadata_,
+ ops->SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
@@ -1025,7 +1025,7 @@ class ServerAsyncReaderWriter final
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -1075,7 +1075,7 @@ class ServerAsyncReaderWriter final
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
- write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
@@ -1094,7 +1094,7 @@ class ServerAsyncReaderWriter final
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -1106,7 +1106,7 @@ class ServerAsyncReaderWriter final
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
- ops->SendInitialMetadata(ctx_->initial_metadata_,
+ ops->SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h
index 60ff8e2f05..89dcb12418 100644
--- a/include/grpcpp/impl/codegen/async_unary_call.h
+++ b/include/grpcpp/impl/codegen/async_unary_call.h
@@ -174,7 +174,7 @@ class ClientAsyncResponseReader final
}
void StartCallInternal() {
- single_buf.SendInitialMetadata(context_->send_initial_metadata_,
+ single_buf.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
}
@@ -214,7 +214,7 @@ class ServerAsyncResponseWriter final
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_buf_.set_output_tag(tag);
- meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
@@ -240,8 +240,9 @@ class ServerAsyncResponseWriter final
/// metadata.
void Finish(const W& msg, const Status& status, void* tag) {
finish_buf_.set_output_tag(tag);
+ finish_buf_.set_core_cq_tag(&finish_buf_);
if (!ctx_->sent_initial_metadata_) {
- finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
@@ -250,10 +251,10 @@ class ServerAsyncResponseWriter final
}
// The response is dropped if the status is not OK.
if (status.ok()) {
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_buf_.SendMessage(msg));
} else {
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_buf_);
}
@@ -274,14 +275,14 @@ class ServerAsyncResponseWriter final
GPR_CODEGEN_ASSERT(!status.ok());
finish_buf_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_buf_);
}
diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h
index 8cc5158115..53ecb53371 100644
--- a/include/grpcpp/impl/codegen/byte_buffer.h
+++ b/include/grpcpp/impl/codegen/byte_buffer.h
@@ -45,11 +45,20 @@ template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
+template <class RequestType, class ResponseType>
+class CallbackUnaryHandler;
+template <class RequestType, class ResponseType>
+class CallbackServerStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
template <class R>
class DeserializeFuncType;
class GrpcByteBufferPeer;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+
} // namespace internal
/// A sequence of bytes.
class ByteBuffer final {
@@ -141,11 +150,18 @@ class ByteBuffer final {
template <class R>
friend class internal::CallOpRecvMessage;
friend class internal::CallOpGenericRecvMessage;
- friend class internal::MethodHandler;
+ template <class ServiceType, class RequestType, class ResponseType>
+ friend class RpcMethodHandler;
+ template <class ServiceType, class RequestType, class ResponseType>
+ friend class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::ServerStreamingHandler;
+ template <class RequestType, class ResponseType>
+ friend class internal::CallbackUnaryHandler;
+ template <class RequestType, class ResponseType>
+ friend class ::grpc::internal::CallbackServerStreamingHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
template <class R>
diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h
index 789ea805a3..c040c30dd9 100644
--- a/include/grpcpp/impl/codegen/call.h
+++ b/include/grpcpp/impl/codegen/call.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,671 +15,31 @@
* limitations under the License.
*
*/
-
#ifndef GRPCPP_IMPL_CODEGEN_CALL_H
#define GRPCPP_IMPL_CODEGEN_CALL_H
-#include <assert.h>
-#include <cstring>
-#include <functional>
-#include <map>
-#include <memory>
-
-#include <grpcpp/impl/codegen/byte_buffer.h>
-#include <grpcpp/impl/codegen/call_hook.h>
-#include <grpcpp/impl/codegen/client_context.h>
-#include <grpcpp/impl/codegen/completion_queue_tag.h>
-#include <grpcpp/impl/codegen/config.h>
-#include <grpcpp/impl/codegen/core_codegen_interface.h>
-#include <grpcpp/impl/codegen/serialization_traits.h>
-#include <grpcpp/impl/codegen/slice.h>
-#include <grpcpp/impl/codegen/status.h>
-#include <grpcpp/impl/codegen/string_ref.h>
-
-#include <grpc/impl/codegen/atm.h>
-#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/call_hook.h>
namespace grpc {
-
-class ByteBuffer;
class CompletionQueue;
-extern CoreCodegenInterface* g_core_codegen_interface;
+namespace experimental {
+class ClientRpcInfo;
+class ServerRpcInfo;
+} // namespace experimental
namespace internal {
-class Call;
class CallHook;
-
-// TODO(yangg) if the map is changed before we send, the pointers will be a
-// mess. Make sure it does not happen.
-inline grpc_metadata* FillMetadataArray(
- const std::multimap<grpc::string, grpc::string>& metadata,
- size_t* metadata_count, const grpc::string& optional_error_details) {
- *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
- if (*metadata_count == 0) {
- return nullptr;
- }
- grpc_metadata* metadata_array =
- (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
- (*metadata_count) * sizeof(grpc_metadata)));
- size_t i = 0;
- for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
- metadata_array[i].key = SliceReferencingString(iter->first);
- metadata_array[i].value = SliceReferencingString(iter->second);
- }
- if (!optional_error_details.empty()) {
- metadata_array[i].key =
- g_core_codegen_interface->grpc_slice_from_static_buffer(
- kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
- metadata_array[i].value = SliceReferencingString(optional_error_details);
- }
- return metadata_array;
-}
-} // namespace internal
-
-/// Per-message write options.
-class WriteOptions {
- public:
- WriteOptions() : flags_(0), last_message_(false) {}
- WriteOptions(const WriteOptions& other)
- : flags_(other.flags_), last_message_(other.last_message_) {}
-
- /// Clear all flags.
- inline void Clear() { flags_ = 0; }
-
- /// Returns raw flags bitset.
- inline uint32_t flags() const { return flags_; }
-
- /// Sets flag for the disabling of compression for the next message write.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline WriteOptions& set_no_compression() {
- SetBit(GRPC_WRITE_NO_COMPRESS);
- return *this;
- }
-
- /// Clears flag for the disabling of compression for the next message write.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline WriteOptions& clear_no_compression() {
- ClearBit(GRPC_WRITE_NO_COMPRESS);
- return *this;
- }
-
- /// Get value for the flag indicating whether compression for the next
- /// message write is forcefully disabled.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline bool get_no_compression() const {
- return GetBit(GRPC_WRITE_NO_COMPRESS);
- }
-
- /// Sets flag indicating that the write may be buffered and need not go out on
- /// the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline WriteOptions& set_buffer_hint() {
- SetBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- /// Clears flag indicating that the write may be buffered and need not go out
- /// on the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline WriteOptions& clear_buffer_hint() {
- ClearBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- /// Get value for the flag indicating that the write may be buffered and need
- /// not go out on the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
- /// corked bit: aliases set_buffer_hint currently, with the intent that
- /// set_buffer_hint will be removed in the future
- inline WriteOptions& set_corked() {
- SetBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- inline WriteOptions& clear_corked() {
- ClearBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
- /// last-message bit: indicates this is the last message in a stream
- /// client-side: makes Write the equivalent of performing Write, WritesDone
- /// in a single step
- /// server-side: hold the Write until the service handler returns (sync api)
- /// or until Finish is called (async api)
- inline WriteOptions& set_last_message() {
- last_message_ = true;
- return *this;
- }
-
- /// Clears flag indicating that this is the last message in a stream,
- /// disabling coalescing.
- inline WriteOptions& clear_last_message() {
- last_message_ = false;
- return *this;
- }
-
- /// Guarantee that all bytes have been written to the socket before completing
- /// this write (usually writes are completed when they pass flow control).
- inline WriteOptions& set_write_through() {
- SetBit(GRPC_WRITE_THROUGH);
- return *this;
- }
-
- inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
-
- /// Get value for the flag indicating that this is the last message, and
- /// should be coalesced with trailing metadata.
- ///
- /// \sa GRPC_WRITE_LAST_MESSAGE
- bool is_last_message() const { return last_message_; }
-
- WriteOptions& operator=(const WriteOptions& rhs) {
- flags_ = rhs.flags_;
- return *this;
- }
-
- private:
- void SetBit(const uint32_t mask) { flags_ |= mask; }
-
- void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
-
- bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
-
- uint32_t flags_;
- bool last_message_;
-};
-
-namespace internal {
-/// Default argument for CallOpSet. I is unused by the class, but can be
-/// used for generating multiple names for the same thing.
-template <int I>
-class CallNoOp {
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {}
- void FinishOp(bool* status) {}
-};
-
-class CallOpSendInitialMetadata {
- public:
- CallOpSendInitialMetadata() : send_(false) {
- maybe_compression_level_.is_set = false;
- }
-
- void SendInitialMetadata(
- const std::multimap<grpc::string, grpc::string>& metadata,
- uint32_t flags) {
- maybe_compression_level_.is_set = false;
- send_ = true;
- flags_ = flags;
- initial_metadata_ =
- FillMetadataArray(metadata, &initial_metadata_count_, "");
- }
-
- void set_compression_level(grpc_compression_level level) {
- maybe_compression_level_.is_set = true;
- maybe_compression_level_.level = level;
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_INITIAL_METADATA;
- op->flags = flags_;
- op->reserved = NULL;
- op->data.send_initial_metadata.count = initial_metadata_count_;
- op->data.send_initial_metadata.metadata = initial_metadata_;
- op->data.send_initial_metadata.maybe_compression_level.is_set =
- maybe_compression_level_.is_set;
- if (maybe_compression_level_.is_set) {
- op->data.send_initial_metadata.maybe_compression_level.level =
- maybe_compression_level_.level;
- }
- }
- void FinishOp(bool* status) {
- if (!send_) return;
- g_core_codegen_interface->gpr_free(initial_metadata_);
- send_ = false;
- }
-
- bool send_;
- uint32_t flags_;
- size_t initial_metadata_count_;
- grpc_metadata* initial_metadata_;
- struct {
- bool is_set;
- grpc_compression_level level;
- } maybe_compression_level_;
-};
-
-class CallOpSendMessage {
- public:
- CallOpSendMessage() : send_buf_() {}
-
- /// Send \a message using \a options for the write. The \a options are cleared
- /// after use.
- template <class M>
- Status SendMessage(const M& message,
- WriteOptions options) GRPC_MUST_USE_RESULT;
-
- template <class M>
- Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_buf_.Valid()) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_MESSAGE;
- op->flags = write_options_.flags();
- op->reserved = NULL;
- op->data.send_message.send_message = send_buf_.c_buffer();
- // Flags are per-message: clear them after use.
- write_options_.Clear();
- }
- void FinishOp(bool* status) { send_buf_.Clear(); }
-
- private:
- ByteBuffer send_buf_;
- WriteOptions write_options_;
-};
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
- write_options_ = options;
- bool own_buf;
- // TODO(vjpai): Remove the void below when possible
- // The void in the template parameter below should not be needed
- // (since it should be implicit) but is needed due to an observed
- // difference in behavior between clang and gcc for certain internal users
- Status result = SerializationTraits<M, void>::Serialize(
- message, send_buf_.bbuf_ptr(), &own_buf);
- if (!own_buf) {
- send_buf_.Duplicate();
- }
- return result;
-}
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message) {
- return SendMessage(message, WriteOptions());
-}
-
-template <class R>
-class CallOpRecvMessage {
- public:
- CallOpRecvMessage()
- : got_message(false),
- message_(nullptr),
- allow_not_getting_message_(false) {}
-
- void RecvMessage(R* message) { message_ = message; }
-
- // Do not change status if no message is received.
- void AllowNoMessage() { allow_not_getting_message_ = true; }
-
- bool got_message;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (message_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_MESSAGE;
- op->flags = 0;
- op->reserved = NULL;
- op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
- }
-
- void FinishOp(bool* status) {
- if (message_ == nullptr) return;
- if (recv_buf_.Valid()) {
- if (*status) {
- got_message = *status =
- SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
- .ok();
- recv_buf_.Release();
- } else {
- got_message = false;
- recv_buf_.Clear();
- }
- } else {
- got_message = false;
- if (!allow_not_getting_message_) {
- *status = false;
- }
- }
- message_ = nullptr;
- }
-
- private:
- R* message_;
- ByteBuffer recv_buf_;
- bool allow_not_getting_message_;
-};
-
-class DeserializeFunc {
- public:
- virtual Status Deserialize(ByteBuffer* buf) = 0;
- virtual ~DeserializeFunc() {}
-};
-
-template <class R>
-class DeserializeFuncType final : public DeserializeFunc {
- public:
- DeserializeFuncType(R* message) : message_(message) {}
- Status Deserialize(ByteBuffer* buf) override {
- return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
- }
-
- ~DeserializeFuncType() override {}
-
- private:
- R* message_; // Not a managed pointer because management is external to this
-};
-
-class CallOpGenericRecvMessage {
- public:
- CallOpGenericRecvMessage()
- : got_message(false), allow_not_getting_message_(false) {}
-
- template <class R>
- void RecvMessage(R* message) {
- // Use an explicit base class pointer to avoid resolution error in the
- // following unique_ptr::reset for some old implementations.
- DeserializeFunc* func = new DeserializeFuncType<R>(message);
- deserialize_.reset(func);
- }
-
- // Do not change status if no message is received.
- void AllowNoMessage() { allow_not_getting_message_ = true; }
-
- bool got_message;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!deserialize_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_MESSAGE;
- op->flags = 0;
- op->reserved = NULL;
- op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
- }
-
- void FinishOp(bool* status) {
- if (!deserialize_) return;
- if (recv_buf_.Valid()) {
- if (*status) {
- got_message = true;
- *status = deserialize_->Deserialize(&recv_buf_).ok();
- recv_buf_.Release();
- } else {
- got_message = false;
- recv_buf_.Clear();
- }
- } else {
- got_message = false;
- if (!allow_not_getting_message_) {
- *status = false;
- }
- }
- deserialize_.reset();
- }
-
- private:
- std::unique_ptr<DeserializeFunc> deserialize_;
- ByteBuffer recv_buf_;
- bool allow_not_getting_message_;
-};
-
-class CallOpClientSendClose {
- public:
- CallOpClientSendClose() : send_(false) {}
-
- void ClientSendClose() { send_ = true; }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
- op->flags = 0;
- op->reserved = NULL;
- }
- void FinishOp(bool* status) { send_ = false; }
-
- private:
- bool send_;
-};
-
-class CallOpServerSendStatus {
- public:
- CallOpServerSendStatus() : send_status_available_(false) {}
-
- void ServerSendStatus(
- const std::multimap<grpc::string, grpc::string>& trailing_metadata,
- const Status& status) {
- send_error_details_ = status.error_details();
- trailing_metadata_ = FillMetadataArray(
- trailing_metadata, &trailing_metadata_count_, send_error_details_);
- send_status_available_ = true;
- send_status_code_ = static_cast<grpc_status_code>(status.error_code());
- send_error_message_ = status.error_message();
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_status_available_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
- op->data.send_status_from_server.trailing_metadata_count =
- trailing_metadata_count_;
- op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
- op->data.send_status_from_server.status = send_status_code_;
- error_message_slice_ = SliceReferencingString(send_error_message_);
- op->data.send_status_from_server.status_details =
- send_error_message_.empty() ? nullptr : &error_message_slice_;
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (!send_status_available_) return;
- g_core_codegen_interface->gpr_free(trailing_metadata_);
- send_status_available_ = false;
- }
-
- private:
- bool send_status_available_;
- grpc_status_code send_status_code_;
- grpc::string send_error_details_;
- grpc::string send_error_message_;
- size_t trailing_metadata_count_;
- grpc_metadata* trailing_metadata_;
- grpc_slice error_message_slice_;
-};
-
-class CallOpRecvInitialMetadata {
- public:
- CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
-
- void RecvInitialMetadata(ClientContext* context) {
- context->initial_metadata_received_ = true;
- metadata_map_ = &context->recv_initial_metadata_;
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (metadata_map_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_INITIAL_METADATA;
- op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (metadata_map_ == nullptr) return;
- metadata_map_ = nullptr;
- }
-
- private:
- MetadataMap* metadata_map_;
-};
-
-class CallOpClientRecvStatus {
- public:
- CallOpClientRecvStatus()
- : recv_status_(nullptr), debug_error_string_(nullptr) {}
-
- void ClientRecvStatus(ClientContext* context, Status* status) {
- client_context_ = context;
- metadata_map_ = &client_context_->trailing_metadata_;
- recv_status_ = status;
- error_message_ = g_core_codegen_interface->grpc_empty_slice();
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (recv_status_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
- op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
- op->data.recv_status_on_client.status = &status_code_;
- op->data.recv_status_on_client.status_details = &error_message_;
- op->data.recv_status_on_client.error_string = &debug_error_string_;
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (recv_status_ == nullptr) return;
- grpc::string binary_error_details = metadata_map_->GetBinaryErrorDetails();
- *recv_status_ =
- Status(static_cast<StatusCode>(status_code_),
- GRPC_SLICE_IS_EMPTY(error_message_)
- ? grpc::string()
- : grpc::string(GRPC_SLICE_START_PTR(error_message_),
- GRPC_SLICE_END_PTR(error_message_)),
- binary_error_details);
- client_context_->set_debug_error_string(
- debug_error_string_ != nullptr ? debug_error_string_ : "");
- g_core_codegen_interface->grpc_slice_unref(error_message_);
- if (debug_error_string_ != nullptr) {
- g_core_codegen_interface->gpr_free((void*)debug_error_string_);
- }
- recv_status_ = nullptr;
- }
-
- private:
- ClientContext* client_context_;
- MetadataMap* metadata_map_;
- Status* recv_status_;
- const char* debug_error_string_;
- grpc_status_code status_code_;
- grpc_slice error_message_;
-};
-
-/// An abstract collection of call ops, used to generate the
-/// grpc_call_op structure to pass down to the lower layers,
-/// and as it is-a CompletionQueueTag, also massages the final
-/// completion into the correct form for consumption in the C++
-/// API.
-class CallOpSetInterface : public CompletionQueueTag {
- public:
- /// Fills in grpc_op, starting from ops[*nops] and moving
- /// upwards.
- virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0;
-
- /// Get the tag to be used at the core completion queue. Generally, the
- /// value of cq_tag will be "this". However, it can be overridden if we
- /// want core to process the tag differently (e.g., as a core callback)
- virtual void* cq_tag() = 0;
-};
-
-/// Primary implementation of CallOpSetInterface.
-/// Since we cannot use variadic templates, we declare slots up to
-/// the maximum count of ops we'll need in a set. We leverage the
-/// empty base class optimization to slim this class (especially
-/// when there are many unused slots used). To avoid duplicate base classes,
-/// the template parmeter for CallNoOp is varied by argument position.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
- class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
- class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class CallOpSet : public CallOpSetInterface,
- public Op1,
- public Op2,
- public Op3,
- public Op4,
- public Op5,
- public Op6 {
- public:
- CallOpSet() : cq_tag_(this), return_tag_(this), call_(nullptr) {}
-
- // The copy constructor and assignment operator reset the value of
- // cq_tag_ and return_tag_ since those are only meaningful on a specific
- // object, not across objects.
- CallOpSet(const CallOpSet& other)
- : cq_tag_(this), return_tag_(this), call_(other.call_) {}
- CallOpSet& operator=(const CallOpSet& other) {
- cq_tag_ = this;
- return_tag_ = this;
- call_ = other.call_;
- return *this;
- }
-
- void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override {
- this->Op1::AddOp(ops, nops);
- this->Op2::AddOp(ops, nops);
- this->Op3::AddOp(ops, nops);
- this->Op4::AddOp(ops, nops);
- this->Op5::AddOp(ops, nops);
- this->Op6::AddOp(ops, nops);
- g_core_codegen_interface->grpc_call_ref(call);
- call_ = call;
- }
-
- bool FinalizeResult(void** tag, bool* status) override {
- this->Op1::FinishOp(status);
- this->Op2::FinishOp(status);
- this->Op3::FinishOp(status);
- this->Op4::FinishOp(status);
- this->Op5::FinishOp(status);
- this->Op6::FinishOp(status);
- *tag = return_tag_;
-
- g_core_codegen_interface->grpc_call_unref(call_);
- return true;
- }
-
- void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
-
- void* cq_tag() override { return cq_tag_; }
-
- /// set_cq_tag is used to provide a different core CQ tag than "this".
- /// This is used for callback-based tags, where the core tag is the core
- /// callback function. It does not change the use or behavior of any other
- /// function (such as FinalizeResult)
- void set_cq_tag(void* cq_tag) { cq_tag_ = cq_tag; }
-
- private:
- void* cq_tag_;
- void* return_tag_;
- grpc_call* call_;
-};
+class CallOpSetInterface;
/// Straightforward wrapping of the C call object
class Call final {
public:
+ Call()
+ : call_hook_(nullptr),
+ cq_(nullptr),
+ call_(nullptr),
+ max_receive_message_size_(-1) {}
/** call is owned by the caller */
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
: call_hook_(call_hook),
@@ -688,11 +48,20 @@ class Call final {
max_receive_message_size_(-1) {}
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
- int max_receive_message_size)
+ experimental::ClientRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
call_(call),
- max_receive_message_size_(max_receive_message_size) {}
+ max_receive_message_size_(-1),
+ client_rpc_info_(rpc_info) {}
+
+ Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
+ int max_receive_message_size, experimental::ServerRpcInfo* rpc_info)
+ : call_hook_(call_hook),
+ cq_(cq),
+ call_(call),
+ max_receive_message_size_(max_receive_message_size),
+ server_rpc_info_(rpc_info) {}
void PerformOps(CallOpSetInterface* ops) {
call_hook_->PerformOpsOnCall(ops, this);
@@ -703,11 +72,21 @@ class Call final {
int max_receive_message_size() const { return max_receive_message_size_; }
+ experimental::ClientRpcInfo* client_rpc_info() const {
+ return client_rpc_info_;
+ }
+
+ experimental::ServerRpcInfo* server_rpc_info() const {
+ return server_rpc_info_;
+ }
+
private:
CallHook* call_hook_;
CompletionQueue* cq_;
grpc_call* call_;
int max_receive_message_size_;
+ experimental::ClientRpcInfo* client_rpc_info_ = nullptr;
+ experimental::ServerRpcInfo* server_rpc_info_ = nullptr;
};
} // namespace internal
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h
new file mode 100644
index 0000000000..b4c34a01c9
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call_op_set.h
@@ -0,0 +1,919 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
+#define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
+
+#include <assert.h>
+#include <array>
+#include <cstring>
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_hook.h>
+#include <grpcpp/impl/codegen/call_op_set_interface.h>
+#include <grpcpp/impl/codegen/client_context.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/intercepted_channel.h>
+#include <grpcpp/impl/codegen/interceptor_common.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+#include <grpc/impl/codegen/atm.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+
+class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+namespace internal {
+class Call;
+class CallHook;
+
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+inline grpc_metadata* FillMetadataArray(
+ const std::multimap<grpc::string, grpc::string>& metadata,
+ size_t* metadata_count, const grpc::string& optional_error_details) {
+ *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
+ if (*metadata_count == 0) {
+ return nullptr;
+ }
+ grpc_metadata* metadata_array =
+ (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
+ (*metadata_count) * sizeof(grpc_metadata)));
+ size_t i = 0;
+ for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
+ metadata_array[i].key = SliceReferencingString(iter->first);
+ metadata_array[i].value = SliceReferencingString(iter->second);
+ }
+ if (!optional_error_details.empty()) {
+ metadata_array[i].key =
+ g_core_codegen_interface->grpc_slice_from_static_buffer(
+ kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
+ metadata_array[i].value = SliceReferencingString(optional_error_details);
+ }
+ return metadata_array;
+}
+} // namespace internal
+
+/// Per-message write options.
+class WriteOptions {
+ public:
+ WriteOptions() : flags_(0), last_message_(false) {}
+ WriteOptions(const WriteOptions& other)
+ : flags_(other.flags_), last_message_(other.last_message_) {}
+
+ /// Clear all flags.
+ inline void Clear() { flags_ = 0; }
+
+ /// Returns raw flags bitset.
+ inline uint32_t flags() const { return flags_; }
+
+ /// Sets flag for the disabling of compression for the next message write.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline WriteOptions& set_no_compression() {
+ SetBit(GRPC_WRITE_NO_COMPRESS);
+ return *this;
+ }
+
+ /// Clears flag for the disabling of compression for the next message write.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline WriteOptions& clear_no_compression() {
+ ClearBit(GRPC_WRITE_NO_COMPRESS);
+ return *this;
+ }
+
+ /// Get value for the flag indicating whether compression for the next
+ /// message write is forcefully disabled.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline bool get_no_compression() const {
+ return GetBit(GRPC_WRITE_NO_COMPRESS);
+ }
+
+ /// Sets flag indicating that the write may be buffered and need not go out on
+ /// the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline WriteOptions& set_buffer_hint() {
+ SetBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ /// Clears flag indicating that the write may be buffered and need not go out
+ /// on the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline WriteOptions& clear_buffer_hint() {
+ ClearBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ /// Get value for the flag indicating that the write may be buffered and need
+ /// not go out on the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+ /// corked bit: aliases set_buffer_hint currently, with the intent that
+ /// set_buffer_hint will be removed in the future
+ inline WriteOptions& set_corked() {
+ SetBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ inline WriteOptions& clear_corked() {
+ ClearBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+ /// last-message bit: indicates this is the last message in a stream
+ /// client-side: makes Write the equivalent of performing Write, WritesDone
+ /// in a single step
+ /// server-side: hold the Write until the service handler returns (sync api)
+ /// or until Finish is called (async api)
+ inline WriteOptions& set_last_message() {
+ last_message_ = true;
+ return *this;
+ }
+
+ /// Clears flag indicating that this is the last message in a stream,
+ /// disabling coalescing.
+ inline WriteOptions& clear_last_message() {
+ last_message_ = false;
+ return *this;
+ }
+
+ /// Guarantee that all bytes have been written to the socket before completing
+ /// this write (usually writes are completed when they pass flow control).
+ inline WriteOptions& set_write_through() {
+ SetBit(GRPC_WRITE_THROUGH);
+ return *this;
+ }
+
+ inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
+
+ /// Get value for the flag indicating that this is the last message, and
+ /// should be coalesced with trailing metadata.
+ ///
+ /// \sa GRPC_WRITE_LAST_MESSAGE
+ bool is_last_message() const { return last_message_; }
+
+ WriteOptions& operator=(const WriteOptions& rhs) {
+ flags_ = rhs.flags_;
+ return *this;
+ }
+
+ private:
+ void SetBit(const uint32_t mask) { flags_ |= mask; }
+
+ void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
+
+ bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
+
+ uint32_t flags_;
+ bool last_message_;
+};
+
+namespace internal {
+
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
+class CallNoOp {
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {}
+ void FinishOp(bool* status) {}
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {}
+};
+
+class CallOpSendInitialMetadata {
+ public:
+ CallOpSendInitialMetadata() : send_(false) {
+ maybe_compression_level_.is_set = false;
+ }
+
+ void SendInitialMetadata(std::multimap<grpc::string, grpc::string>* metadata,
+ uint32_t flags) {
+ maybe_compression_level_.is_set = false;
+ send_ = true;
+ flags_ = flags;
+ metadata_map_ = metadata;
+ }
+
+ void set_compression_level(grpc_compression_level level) {
+ maybe_compression_level_.is_set = true;
+ maybe_compression_level_.level = level;
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->flags = flags_;
+ op->reserved = NULL;
+ initial_metadata_ =
+ FillMetadataArray(*metadata_map_, &initial_metadata_count_, "");
+ op->data.send_initial_metadata.count = initial_metadata_count_;
+ op->data.send_initial_metadata.metadata = initial_metadata_;
+ op->data.send_initial_metadata.maybe_compression_level.is_set =
+ maybe_compression_level_.is_set;
+ if (maybe_compression_level_.is_set) {
+ op->data.send_initial_metadata.maybe_compression_level.level =
+ maybe_compression_level_.level;
+ }
+ }
+ void FinishOp(bool* status) {
+ if (!send_ || hijacked_) return;
+ g_core_codegen_interface->gpr_free(initial_metadata_);
+ send_ = false;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA);
+ interceptor_methods->SetSendInitialMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ bool hijacked_ = false;
+ bool send_;
+ uint32_t flags_;
+ size_t initial_metadata_count_;
+ std::multimap<grpc::string, grpc::string>* metadata_map_;
+ grpc_metadata* initial_metadata_;
+ struct {
+ bool is_set;
+ grpc_compression_level level;
+ } maybe_compression_level_;
+};
+
+class CallOpSendMessage {
+ public:
+ CallOpSendMessage() : send_buf_() {}
+
+ /// Send \a message using \a options for the write. The \a options are cleared
+ /// after use.
+ template <class M>
+ Status SendMessage(const M& message,
+ WriteOptions options) GRPC_MUST_USE_RESULT;
+
+ template <class M>
+ Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_buf_.Valid() || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->flags = write_options_.flags();
+ op->reserved = NULL;
+ op->data.send_message.send_message = send_buf_.c_buffer();
+ // Flags are per-message: clear them after use.
+ write_options_.Clear();
+ }
+ void FinishOp(bool* status) { send_buf_.Clear(); }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_buf_.Valid()) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE);
+ interceptor_methods->SetSendMessage(&send_buf_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ ByteBuffer send_buf_;
+ WriteOptions write_options_;
+};
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
+ write_options_ = options;
+ bool own_buf;
+ // TODO(vjpai): Remove the void below when possible
+ // The void in the template parameter below should not be needed
+ // (since it should be implicit) but is needed due to an observed
+ // difference in behavior between clang and gcc for certain internal users
+ Status result = SerializationTraits<M, void>::Serialize(
+ message, send_buf_.bbuf_ptr(), &own_buf);
+ if (!own_buf) {
+ send_buf_.Duplicate();
+ }
+ return result;
+}
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message) {
+ return SendMessage(message, WriteOptions());
+}
+
+template <class R>
+class CallOpRecvMessage {
+ public:
+ CallOpRecvMessage()
+ : got_message(false),
+ message_(nullptr),
+ allow_not_getting_message_(false) {}
+
+ void RecvMessage(R* message) { message_ = message; }
+
+ // Do not change status if no message is received.
+ void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+ bool got_message;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (message_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->flags = 0;
+ op->reserved = NULL;
+ op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+ }
+
+ void FinishOp(bool* status) {
+ if (message_ == nullptr || hijacked_) return;
+ if (recv_buf_.Valid()) {
+ if (*status) {
+ got_message = *status =
+ SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
+ .ok();
+ recv_buf_.Release();
+ } else {
+ got_message = false;
+ recv_buf_.Clear();
+ }
+ } else {
+ got_message = false;
+ if (!allow_not_getting_message_) {
+ *status = false;
+ }
+ }
+ message_ = nullptr;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvMessage(message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!got_message) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ }
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (message_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
+ got_message = true;
+ }
+
+ private:
+ R* message_;
+ ByteBuffer recv_buf_;
+ bool allow_not_getting_message_;
+ bool hijacked_ = false;
+};
+
+class DeserializeFunc {
+ public:
+ virtual Status Deserialize(ByteBuffer* buf) = 0;
+ virtual ~DeserializeFunc() {}
+};
+
+template <class R>
+class DeserializeFuncType final : public DeserializeFunc {
+ public:
+ DeserializeFuncType(R* message) : message_(message) {}
+ Status Deserialize(ByteBuffer* buf) override {
+ return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
+ }
+
+ ~DeserializeFuncType() override {}
+
+ private:
+ R* message_; // Not a managed pointer because management is external to this
+};
+
+class CallOpGenericRecvMessage {
+ public:
+ CallOpGenericRecvMessage()
+ : got_message(false), allow_not_getting_message_(false) {}
+
+ template <class R>
+ void RecvMessage(R* message) {
+ // Use an explicit base class pointer to avoid resolution error in the
+ // following unique_ptr::reset for some old implementations.
+ DeserializeFunc* func = new DeserializeFuncType<R>(message);
+ deserialize_.reset(func);
+ message_ = message;
+ }
+
+ // Do not change status if no message is received.
+ void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+ bool got_message;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!deserialize_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->flags = 0;
+ op->reserved = NULL;
+ op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+ }
+
+ void FinishOp(bool* status) {
+ if (!deserialize_ || hijacked_) return;
+ if (recv_buf_.Valid()) {
+ if (*status) {
+ got_message = true;
+ *status = deserialize_->Deserialize(&recv_buf_).ok();
+ recv_buf_.Release();
+ } else {
+ got_message = false;
+ recv_buf_.Clear();
+ }
+ } else {
+ got_message = false;
+ if (!allow_not_getting_message_) {
+ *status = false;
+ }
+ }
+ deserialize_.reset();
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvMessage(message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!got_message) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ }
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (!deserialize_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
+ }
+
+ private:
+ void* message_;
+ bool hijacked_ = false;
+ std::unique_ptr<DeserializeFunc> deserialize_;
+ ByteBuffer recv_buf_;
+ bool allow_not_getting_message_;
+};
+
+class CallOpClientSendClose {
+ public:
+ CallOpClientSendClose() : send_(false) {}
+
+ void ClientSendClose() { send_ = true; }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+ void FinishOp(bool* status) { send_ = false; }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ bool send_;
+};
+
+class CallOpServerSendStatus {
+ public:
+ CallOpServerSendStatus() : send_status_available_(false) {}
+
+ void ServerSendStatus(
+ std::multimap<grpc::string, grpc::string>* trailing_metadata,
+ const Status& status) {
+ send_error_details_ = status.error_details();
+ metadata_map_ = trailing_metadata;
+ send_status_available_ = true;
+ send_status_code_ = static_cast<grpc_status_code>(status.error_code());
+ send_error_message_ = status.error_message();
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_status_available_ || hijacked_) return;
+ trailing_metadata_ = FillMetadataArray(
+ *metadata_map_, &trailing_metadata_count_, send_error_details_);
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count =
+ trailing_metadata_count_;
+ op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
+ op->data.send_status_from_server.status = send_status_code_;
+ error_message_slice_ = SliceReferencingString(send_error_message_);
+ op->data.send_status_from_server.status_details =
+ send_error_message_.empty() ? nullptr : &error_message_slice_;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (!send_status_available_ || hijacked_) return;
+ g_core_codegen_interface->gpr_free(trailing_metadata_);
+ send_status_available_ = false;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_status_available_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_STATUS);
+ interceptor_methods->SetSendTrailingMetadata(metadata_map_);
+ interceptor_methods->SetSendStatus(&send_status_code_, &send_error_details_,
+ &send_error_message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ bool send_status_available_;
+ grpc_status_code send_status_code_;
+ grpc::string send_error_details_;
+ grpc::string send_error_message_;
+ size_t trailing_metadata_count_;
+ std::multimap<grpc::string, grpc::string>* metadata_map_;
+ grpc_metadata* trailing_metadata_;
+ grpc_slice error_message_slice_;
+};
+
+class CallOpRecvInitialMetadata {
+ public:
+ CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
+
+ void RecvInitialMetadata(ClientContext* context) {
+ context->initial_metadata_received_ = true;
+ metadata_map_ = &context->recv_initial_metadata_;
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (metadata_map_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (metadata_map_ == nullptr || hijacked_) return;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvInitialMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (metadata_map_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ metadata_map_ = nullptr;
+ }
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (metadata_map_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA);
+ }
+
+ private:
+ bool hijacked_ = false;
+ MetadataMap* metadata_map_;
+};
+
+class CallOpClientRecvStatus {
+ public:
+ CallOpClientRecvStatus()
+ : recv_status_(nullptr), debug_error_string_(nullptr) {}
+
+ void ClientRecvStatus(ClientContext* context, Status* status) {
+ client_context_ = context;
+ metadata_map_ = &client_context_->trailing_metadata_;
+ recv_status_ = status;
+ error_message_ = g_core_codegen_interface->grpc_empty_slice();
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (recv_status_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
+ op->data.recv_status_on_client.status = &status_code_;
+ op->data.recv_status_on_client.status_details = &error_message_;
+ op->data.recv_status_on_client.error_string = &debug_error_string_;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (recv_status_ == nullptr || hijacked_) return;
+ grpc::string binary_error_details = metadata_map_->GetBinaryErrorDetails();
+ *recv_status_ =
+ Status(static_cast<StatusCode>(status_code_),
+ GRPC_SLICE_IS_EMPTY(error_message_)
+ ? grpc::string()
+ : grpc::string(GRPC_SLICE_START_PTR(error_message_),
+ GRPC_SLICE_END_PTR(error_message_)),
+ binary_error_details);
+ client_context_->set_debug_error_string(
+ debug_error_string_ != nullptr ? debug_error_string_ : "");
+ g_core_codegen_interface->grpc_slice_unref(error_message_);
+ if (debug_error_string_ != nullptr) {
+ g_core_codegen_interface->gpr_free((void*)debug_error_string_);
+ }
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvStatus(recv_status_);
+ interceptor_methods->SetRecvTrailingMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (recv_status_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS);
+ recv_status_ = nullptr;
+ }
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (recv_status_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS);
+ }
+
+ private:
+ bool hijacked_ = false;
+ ClientContext* client_context_;
+ MetadataMap* metadata_map_;
+ Status* recv_status_;
+ const char* debug_error_string_;
+ grpc_status_code status_code_;
+ grpc_slice error_message_;
+};
+
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+ class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+ class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class CallOpSet;
+
+/// Primary implementation of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
+class CallOpSet : public CallOpSetInterface,
+ public Op1,
+ public Op2,
+ public Op3,
+ public Op4,
+ public Op5,
+ public Op6 {
+ public:
+ CallOpSet() : core_cq_tag_(this), return_tag_(this) {}
+ // The copy constructor and assignment operator reset the value of
+ // core_cq_tag_, return_tag_, done_intercepting_ and interceptor_methods_
+ // since those are only meaningful on a specific object, not across objects.
+ CallOpSet(const CallOpSet& other)
+ : core_cq_tag_(this),
+ return_tag_(this),
+ call_(other.call_),
+ done_intercepting_(false),
+ interceptor_methods_(InterceptorBatchMethodsImpl()) {}
+
+ CallOpSet& operator=(const CallOpSet& other) {
+ core_cq_tag_ = this;
+ return_tag_ = this;
+ call_ = other.call_;
+ done_intercepting_ = false;
+ interceptor_methods_ = InterceptorBatchMethodsImpl();
+ return *this;
+ }
+
+ void FillOps(Call* call) override {
+ done_intercepting_ = false;
+ g_core_codegen_interface->grpc_call_ref(call->call());
+ call_ =
+ *call; // It's fine to create a copy of call since it's just pointers
+
+ if (RunInterceptors()) {
+ ContinueFillOpsAfterInterception();
+ } else {
+ // After the interceptors are run, ContinueFillOpsAfterInterception will
+ // be run
+ }
+ }
+
+ bool FinalizeResult(void** tag, bool* status) override {
+ if (done_intercepting_) {
+ // We have already finished intercepting and filling in the results. This
+ // round trip from the core needed to be made because interceptors were
+ // run
+ *tag = return_tag_;
+ *status = saved_status_;
+ g_core_codegen_interface->grpc_call_unref(call_.call());
+ return true;
+ }
+
+ this->Op1::FinishOp(status);
+ this->Op2::FinishOp(status);
+ this->Op3::FinishOp(status);
+ this->Op4::FinishOp(status);
+ this->Op5::FinishOp(status);
+ this->Op6::FinishOp(status);
+ saved_status_ = *status;
+ if (RunInterceptorsPostRecv()) {
+ *tag = return_tag_;
+ g_core_codegen_interface->grpc_call_unref(call_.call());
+ return true;
+ }
+ // Interceptors are going to be run, so we can't return the tag just yet.
+ // After the interceptors are run, ContinueFinalizeResultAfterInterception
+ return false;
+ }
+
+ void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+
+ void* core_cq_tag() override { return core_cq_tag_; }
+
+ /// set_core_cq_tag is used to provide a different core CQ tag than "this".
+ /// This is used for callback-based tags, where the core tag is the core
+ /// callback function. It does not change the use or behavior of any other
+ /// function (such as FinalizeResult)
+ void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; }
+
+ // This will be called while interceptors are run if the RPC is a hijacked
+ // RPC. This should set hijacking state for each of the ops.
+ void SetHijackingState() override {
+ this->Op1::SetHijackingState(&interceptor_methods_);
+ this->Op2::SetHijackingState(&interceptor_methods_);
+ this->Op3::SetHijackingState(&interceptor_methods_);
+ this->Op4::SetHijackingState(&interceptor_methods_);
+ this->Op5::SetHijackingState(&interceptor_methods_);
+ this->Op6::SetHijackingState(&interceptor_methods_);
+ }
+
+ // Should be called after interceptors are done running
+ void ContinueFillOpsAfterInterception() override {
+ static const size_t MAX_OPS = 6;
+ grpc_op ops[MAX_OPS];
+ size_t nops = 0;
+ this->Op1::AddOp(ops, &nops);
+ this->Op2::AddOp(ops, &nops);
+ this->Op3::AddOp(ops, &nops);
+ this->Op4::AddOp(ops, &nops);
+ this->Op5::AddOp(ops, &nops);
+ this->Op6::AddOp(ops, &nops);
+ GPR_CODEGEN_ASSERT(GRPC_CALL_OK ==
+ g_core_codegen_interface->grpc_call_start_batch(
+ call_.call(), ops, nops, core_cq_tag(), nullptr));
+ }
+
+ // Should be called after interceptors are done running on the finalize result
+ // path
+ void ContinueFinalizeResultAfterInterception() override {
+ done_intercepting_ = true;
+ GPR_CODEGEN_ASSERT(GRPC_CALL_OK ==
+ g_core_codegen_interface->grpc_call_start_batch(
+ call_.call(), nullptr, 0, core_cq_tag(), nullptr));
+ }
+
+ private:
+ // Returns true if no interceptors need to be run
+ bool RunInterceptors() {
+ interceptor_methods_.ClearState();
+ interceptor_methods_.SetCallOpSetInterface(this);
+ interceptor_methods_.SetCall(&call_);
+ this->Op1::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op2::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op3::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op4::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op5::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op6::SetInterceptionHookPoint(&interceptor_methods_);
+ return interceptor_methods_.RunInterceptors();
+ }
+ // Returns true if no interceptors need to be run
+ bool RunInterceptorsPostRecv() {
+ // Call and OpSet had already been set on the set state.
+ // SetReverse also clears previously set hook points
+ interceptor_methods_.SetReverse();
+ this->Op1::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op2::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op3::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op4::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op5::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op6::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ return interceptor_methods_.RunInterceptors();
+ }
+
+ void* core_cq_tag_;
+ void* return_tag_;
+ Call call_;
+ bool done_intercepting_ = false;
+ InterceptorBatchMethodsImpl interceptor_methods_;
+ bool saved_status_;
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
diff --git a/include/grpcpp/impl/codegen/call_op_set_interface.h b/include/grpcpp/impl/codegen/call_op_set_interface.h
new file mode 100644
index 0000000000..3b74566a6d
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call_op_set_interface.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
+#define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
+
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+
+namespace grpc {
+namespace internal {
+
+class Call;
+
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
+class CallOpSetInterface : public CompletionQueueTag {
+ public:
+ /// Fills in grpc_op, starting from ops[*nops] and moving
+ /// upwards.
+ virtual void FillOps(internal::Call* call) = 0;
+
+ /// Get the tag to be used at the core completion queue. Generally, the
+ /// value of core_cq_tag will be "this". However, it can be overridden if we
+ /// want core to process the tag differently (e.g., as a core callback)
+ virtual void* core_cq_tag() = 0;
+
+ // This will be called while interceptors are run if the RPC is a hijacked
+ // RPC. This should set hijacking state for each of the ops.
+ virtual void SetHijackingState() = 0;
+
+ // Should be called after interceptors are done running
+ virtual void ContinueFillOpsAfterInterception() = 0;
+
+ // Should be called after interceptors are done running on the finalize result
+ // path
+ virtual void ContinueFinalizeResultAfterInterception() = 0;
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
diff --git a/include/grpcpp/impl/codegen/callback_common.h b/include/grpcpp/impl/codegen/callback_common.h
index a9835973ac..a3c8c41246 100644
--- a/include/grpcpp/impl/codegen/callback_common.h
+++ b/include/grpcpp/impl/codegen/callback_common.h
@@ -32,6 +32,8 @@ namespace grpc {
namespace internal {
/// An exception-safe way of invoking a user-specified callback function
+// TODO(vjpai): decide whether it is better for this to take a const lvalue
+// parameter or an rvalue parameter, or if it even matters
template <class Func, class... Args>
void CatchingCallback(Func&& func, Args&&... args) {
#if GRPC_ALLOW_EXCEPTIONS
@@ -45,6 +47,20 @@ void CatchingCallback(Func&& func, Args&&... args) {
#endif // GRPC_ALLOW_EXCEPTIONS
}
+template <class ReturnType, class Func, class... Args>
+ReturnType* CatchingReactorCreator(Func&& func, Args&&... args) {
+#if GRPC_ALLOW_EXCEPTIONS
+ try {
+ return func(std::forward<Args>(args)...);
+ } catch (...) {
+ // fail the RPC, don't crash the library
+ return nullptr;
+ }
+#else // GRPC_ALLOW_EXCEPTIONS
+ return func(std::forward<Args>(args)...);
+#endif // GRPC_ALLOW_EXCEPTIONS
+}
+
// The contract on these tags is that they are single-shot. They must be
// constructed and then fired at exactly one point. There is no expectation
// that they can be reused without reconstruction.
@@ -94,18 +110,25 @@ class CallbackWithStatusTag
void Run(bool ok) {
void* ignored = ops_;
- GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &ok));
+ if (!ops_->FinalizeResult(&ignored, &ok)) {
+ // The tag was swallowed
+ return;
+ }
GPR_CODEGEN_ASSERT(ignored == ops_);
// Last use of func_ or status_, so ok to move them out
- CatchingCallback(std::move(func_), std::move(status_));
-
+ auto func = std::move(func_);
+ auto status = std::move(status_);
func_ = nullptr; // reset to clear this out for sure
status_ = Status(); // reset to clear this out for sure
+ CatchingCallback(std::move(func), std::move(status));
g_core_codegen_interface->grpc_call_unref(call_);
}
};
+/// CallbackWithSuccessTag can be reused multiple times, and will be used in
+/// this fashion for streaming operations. As a result, it shouldn't clear
+/// anything up until its destructor
class CallbackWithSuccessTag
: public grpc_experimental_completion_queue_functor {
public:
@@ -121,13 +144,40 @@ class CallbackWithSuccessTag
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { assert(0); }
+ CallbackWithSuccessTag() : call_(nullptr) {}
+
CallbackWithSuccessTag(grpc_call* call, std::function<void(bool)> f,
- CompletionQueueTag* ops)
- : call_(call), func_(std::move(f)), ops_(ops) {
+ CompletionQueueTag* ops) {
+ Set(call, f, ops);
+ }
+
+ CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete;
+ CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete;
+
+ ~CallbackWithSuccessTag() { Clear(); }
+
+ // Set can only be called on a default-constructed or Clear'ed tag.
+ // It should never be called on a tag that was constructed with arguments
+ // or on a tag that has been Set before unless the tag has been cleared.
+ void Set(grpc_call* call, std::function<void(bool)> f,
+ CompletionQueueTag* ops) {
+ GPR_CODEGEN_ASSERT(call_ == nullptr);
g_core_codegen_interface->grpc_call_ref(call);
+ call_ = call;
+ func_ = std::move(f);
+ ops_ = ops;
functor_run = &CallbackWithSuccessTag::StaticRun;
}
+ void Clear() {
+ if (call_ != nullptr) {
+ grpc_call* call = call_;
+ call_ = nullptr;
+ func_ = nullptr;
+ g_core_codegen_interface->grpc_call_unref(call);
+ }
+ }
+
CompletionQueueTag* ops() { return ops_; }
// force_run can not be performed on a tag if operations using this tag
@@ -135,6 +185,9 @@ class CallbackWithSuccessTag
// that are detected before the operations are internally processed.
void force_run(bool ok) { Run(ok); }
+ /// check if this tag is currently set
+ operator bool() const { return call_ != nullptr; }
+
private:
grpc_call* call_;
std::function<void(bool)> func_;
@@ -146,15 +199,15 @@ class CallbackWithSuccessTag
}
void Run(bool ok) {
void* ignored = ops_;
- bool new_ok = ok;
- GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &new_ok));
- GPR_CODEGEN_ASSERT(ignored == ops_);
-
- // Last use of func_, so ok to move it out for rvalue call above
- CatchingCallback(std::move(func_), ok);
-
- func_ = nullptr; // reset to clear this out for sure
- g_core_codegen_interface->grpc_call_unref(call_);
+ // Allow a "false" return value from FinalizeResult to silence the
+ // callback, just as it silences a CQ tag in the async cases
+ auto* ops = ops_;
+ bool do_callback = ops_->FinalizeResult(&ignored, &ok);
+ GPR_CODEGEN_ASSERT(ignored == ops);
+
+ if (do_callback) {
+ CatchingCallback(func_, ok);
+ }
}
};
diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h
index b257acc1ab..5353f5feaa 100644
--- a/include/grpcpp/impl/codegen/channel_interface.h
+++ b/include/grpcpp/impl/codegen/channel_interface.h
@@ -20,6 +20,7 @@
#define GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
@@ -51,6 +52,13 @@ template <class W, class R>
class ClientAsyncReaderWriterFactory;
template <class R>
class ClientAsyncResponseReaderFactory;
+template <class W, class R>
+class ClientCallbackReaderWriterFactory;
+template <class R>
+class ClientCallbackReaderFactory;
+template <class W>
+class ClientCallbackWriterFactory;
+class InterceptedChannel;
} // namespace internal
/// Codegen interface for \a grpc::Channel.
@@ -103,11 +111,18 @@ class ChannelInterface {
friend class ::grpc::internal::ClientAsyncReaderWriterFactory;
template <class R>
friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
+ template <class W, class R>
+ friend class ::grpc::internal::ClientCallbackReaderWriterFactory;
+ template <class R>
+ friend class ::grpc::internal::ClientCallbackReaderFactory;
+ template <class W>
+ friend class ::grpc::internal::ClientCallbackWriterFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
friend class ::grpc::internal::RpcMethod;
+ friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq) = 0;
@@ -121,11 +136,25 @@ class ChannelInterface {
gpr_timespec deadline) = 0;
// EXPERIMENTAL
+ // This is needed to keep codegen_test_minimal happy. InterceptedChannel needs
+ // to make use of this but can't directly call Channel's implementation
+ // because of the test.
+ // Returns an empty Call object (rather than being pure) since this is a new
+ // method and adding a new pure method to an interface would be a breaking
+ // change (even though this is private and non-API)
+ virtual internal::Call CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq,
+ size_t interceptor_pos) {
+ return internal::Call();
+ }
+
+ // EXPERIMENTAL
// A method to get the callbackable completion queue associated with this
// channel. If the return value is nullptr, this channel doesn't support
// callback operations.
// TODO(vjpai): Consider a better default like using a global CQ
- // Returns nullptr (rather than being pure) since this is a new method
+ // Returns nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual CompletionQueue* CallbackCQ() { return nullptr; }
diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h
index 4d4faea063..66cf9b7754 100644
--- a/include/grpcpp/impl/codegen/client_callback.h
+++ b/include/grpcpp/impl/codegen/client_callback.h
@@ -22,6 +22,7 @@
#include <functional>
#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/config.h>
@@ -77,17 +78,671 @@ class CallbackUnaryCallImpl {
tag->force_run(s);
return;
}
- ops->SendInitialMetadata(context->send_initial_metadata_,
+ ops->SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
ops->RecvInitialMetadata(context);
ops->RecvMessage(result);
ops->AllowNoMessage();
ops->ClientSendClose();
ops->ClientRecvStatus(context, tag->status_ptr());
- ops->set_cq_tag(tag);
+ ops->set_core_cq_tag(tag);
call.PerformOps(ops);
}
};
+} // namespace internal
+
+namespace experimental {
+
+// Forward declarations
+template <class Request, class Response>
+class ClientBidiReactor;
+template <class Response>
+class ClientReadReactor;
+template <class Request>
+class ClientWriteReactor;
+
+// NOTE: The streaming objects are not actually implemented in the public API.
+// These interfaces are provided for mocking only. Typical applications
+// will interact exclusively with the reactors that they define.
+template <class Request, class Response>
+class ClientCallbackReaderWriter {
+ public:
+ virtual ~ClientCallbackReaderWriter() {}
+ virtual void StartCall() = 0;
+ virtual void Write(const Request* req, WriteOptions options) = 0;
+ virtual void WritesDone() = 0;
+ virtual void Read(Response* resp) = 0;
+
+ protected:
+ void BindReactor(ClientBidiReactor<Request, Response>* reactor) {
+ reactor->BindStream(this);
+ }
+};
+
+template <class Response>
+class ClientCallbackReader {
+ public:
+ virtual ~ClientCallbackReader() {}
+ virtual void StartCall() = 0;
+ virtual void Read(Response* resp) = 0;
+
+ protected:
+ void BindReactor(ClientReadReactor<Response>* reactor) {
+ reactor->BindReader(this);
+ }
+};
+
+template <class Request>
+class ClientCallbackWriter {
+ public:
+ virtual ~ClientCallbackWriter() {}
+ virtual void StartCall() = 0;
+ void Write(const Request* req) { Write(req, WriteOptions()); }
+ virtual void Write(const Request* req, WriteOptions options) = 0;
+ void WriteLast(const Request* req, WriteOptions options) {
+ Write(req, options.set_last_message());
+ }
+ virtual void WritesDone() = 0;
+
+ protected:
+ void BindReactor(ClientWriteReactor<Request>* reactor) {
+ reactor->BindWriter(this);
+ }
+};
+
+// The user must implement this reactor interface with reactions to each event
+// type that gets called by the library. An empty reaction is provided by
+// default
+template <class Request, class Response>
+class ClientBidiReactor {
+ public:
+ virtual ~ClientBidiReactor() {}
+ virtual void OnDone(const Status& s) {}
+ virtual void OnReadInitialMetadataDone(bool ok) {}
+ virtual void OnReadDone(bool ok) {}
+ virtual void OnWriteDone(bool ok) {}
+ virtual void OnWritesDoneDone(bool ok) {}
+
+ void StartCall() { stream_->StartCall(); }
+ void StartRead(Response* resp) { stream_->Read(resp); }
+ void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); }
+ void StartWrite(const Request* req, WriteOptions options) {
+ stream_->Write(req, std::move(options));
+ }
+ void StartWriteLast(const Request* req, WriteOptions options) {
+ StartWrite(req, std::move(options.set_last_message()));
+ }
+ void StartWritesDone() { stream_->WritesDone(); }
+
+ private:
+ friend class ClientCallbackReaderWriter<Request, Response>;
+ void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
+ stream_ = stream;
+ }
+ ClientCallbackReaderWriter<Request, Response>* stream_;
+};
+
+template <class Response>
+class ClientReadReactor {
+ public:
+ virtual ~ClientReadReactor() {}
+ virtual void OnDone(const Status& s) {}
+ virtual void OnReadInitialMetadataDone(bool ok) {}
+ virtual void OnReadDone(bool ok) {}
+
+ void StartCall() { reader_->StartCall(); }
+ void StartRead(Response* resp) { reader_->Read(resp); }
+
+ private:
+ friend class ClientCallbackReader<Response>;
+ void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
+ ClientCallbackReader<Response>* reader_;
+};
+
+template <class Request>
+class ClientWriteReactor {
+ public:
+ virtual ~ClientWriteReactor() {}
+ virtual void OnDone(const Status& s) {}
+ virtual void OnReadInitialMetadataDone(bool ok) {}
+ virtual void OnWriteDone(bool ok) {}
+ virtual void OnWritesDoneDone(bool ok) {}
+
+ void StartCall() { writer_->StartCall(); }
+ void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); }
+ void StartWrite(const Request* req, WriteOptions options) {
+ writer_->Write(req, std::move(options));
+ }
+ void StartWriteLast(const Request* req, WriteOptions options) {
+ StartWrite(req, std::move(options.set_last_message()));
+ }
+ void StartWritesDone() { writer_->WritesDone(); }
+
+ private:
+ friend class ClientCallbackWriter<Request>;
+ void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
+ ClientCallbackWriter<Request>* writer_;
+};
+
+} // namespace experimental
+
+namespace internal {
+
+// Forward declare factory classes for friendship
+template <class Request, class Response>
+class ClientCallbackReaderWriterFactory;
+template <class Response>
+class ClientCallbackReaderFactory;
+template <class Request>
+class ClientCallbackWriterFactory;
+
+template <class Request, class Response>
+class ClientCallbackReaderWriterImpl
+ : public ::grpc::experimental::ClientCallbackReaderWriter<Request,
+ Response> {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(ClientCallbackReaderWriterImpl));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ void MaybeFinish() {
+ if (--callbacks_outstanding_ == 0) {
+ Status s = std::move(finish_status_);
+ auto* reactor = reactor_;
+ auto* call = call_.call();
+ this->~ClientCallbackReaderWriterImpl();
+ g_core_codegen_interface->grpc_call_unref(call);
+ reactor->OnDone(s);
+ }
+ }
+
+ void StartCall() override {
+ // This call initiates two batches, plus any backlog, each with a callback
+ // 1. Send initial metadata (unless corked) + recv initial metadata
+ // 2. Any read backlog
+ // 3. Recv trailing metadata, on_completion callback
+ // 4. Any write backlog
+ // 5. See if the call can finish (if other callbacks were triggered already)
+ started_ = true;
+
+ start_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadInitialMetadataDone(ok);
+ MaybeFinish();
+ },
+ &start_ops_);
+ if (!start_corked_) {
+ start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ }
+ start_ops_.RecvInitialMetadata(context_);
+ start_ops_.set_core_cq_tag(&start_tag_);
+ call_.PerformOps(&start_ops_);
+
+ // Also set up the read and write tags so that they don't have to be set up
+ // each time
+ write_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWriteDone(ok);
+ MaybeFinish();
+ },
+ &write_ops_);
+ write_ops_.set_core_cq_tag(&write_tag_);
+
+ read_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadDone(ok);
+ MaybeFinish();
+ },
+ &read_ops_);
+ read_ops_.set_core_cq_tag(&read_tag_);
+ if (read_ops_at_start_) {
+ call_.PerformOps(&read_ops_);
+ }
+
+ finish_tag_.Set(call_.call(), [this](bool ok) { MaybeFinish(); },
+ &finish_ops_);
+ finish_ops_.ClientRecvStatus(context_, &finish_status_);
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+ call_.PerformOps(&finish_ops_);
+
+ if (write_ops_at_start_) {
+ call_.PerformOps(&write_ops_);
+ }
+
+ if (writes_done_ops_at_start_) {
+ call_.PerformOps(&writes_done_ops_);
+ }
+ MaybeFinish();
+ }
+
+ void Read(Response* msg) override {
+ read_ops_.RecvMessage(msg);
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&read_ops_);
+ } else {
+ read_ops_at_start_ = true;
+ }
+ }
+
+ void Write(const Request* msg, WriteOptions options) override {
+ if (start_corked_) {
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ start_corked_ = false;
+ }
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(write_ops_.SendMessage(*msg).ok());
+
+ if (options.is_last_message()) {
+ options.set_buffer_hint();
+ write_ops_.ClientSendClose();
+ }
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&write_ops_);
+ } else {
+ write_ops_at_start_ = true;
+ }
+ }
+ void WritesDone() override {
+ if (start_corked_) {
+ writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ start_corked_ = false;
+ }
+ writes_done_ops_.ClientSendClose();
+ writes_done_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWritesDoneDone(ok);
+ MaybeFinish();
+ },
+ &writes_done_ops_);
+ writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&writes_done_ops_);
+ } else {
+ writes_done_ops_at_start_ = true;
+ }
+ }
+
+ private:
+ friend class ClientCallbackReaderWriterFactory<Request, Response>;
+
+ ClientCallbackReaderWriterImpl(
+ Call call, ClientContext* context,
+ ::grpc::experimental::ClientBidiReactor<Request, Response>* reactor)
+ : context_(context),
+ call_(call),
+ reactor_(reactor),
+ start_corked_(context_->initial_metadata_corked_) {
+ this->BindReactor(reactor);
+ }
+
+ ClientContext* context_;
+ Call call_;
+ ::grpc::experimental::ClientBidiReactor<Request, Response>* reactor_;
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpRecvInitialMetadata> start_ops_;
+ CallbackWithSuccessTag start_tag_;
+ bool start_corked_;
+
+ CallOpSet<CallOpClientRecvStatus> finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ Status finish_status_;
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
+ write_ops_;
+ CallbackWithSuccessTag write_tag_;
+ bool write_ops_at_start_{false};
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpClientSendClose> writes_done_ops_;
+ CallbackWithSuccessTag writes_done_tag_;
+ bool writes_done_ops_at_start_{false};
+
+ CallOpSet<CallOpRecvMessage<Response>> read_ops_;
+ CallbackWithSuccessTag read_tag_;
+ bool read_ops_at_start_{false};
+
+ // Minimum of 3 callbacks to pre-register for StartCall, start, and finish
+ std::atomic_int callbacks_outstanding_{3};
+ bool started_{false};
+};
+
+template <class Request, class Response>
+class ClientCallbackReaderWriterFactory {
+ public:
+ static void Create(
+ ChannelInterface* channel, const ::grpc::internal::RpcMethod& method,
+ ClientContext* context,
+ ::grpc::experimental::ClientBidiReactor<Request, Response>* reactor) {
+ Call call = channel->CreateCall(method, context, channel->CallbackCQ());
+
+ g_core_codegen_interface->grpc_call_ref(call.call());
+ new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(ClientCallbackReaderWriterImpl<Request, Response>)))
+ ClientCallbackReaderWriterImpl<Request, Response>(call, context,
+ reactor);
+ }
+};
+
+template <class Response>
+class ClientCallbackReaderImpl
+ : public ::grpc::experimental::ClientCallbackReader<Response> {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(ClientCallbackReaderImpl));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ void MaybeFinish() {
+ if (--callbacks_outstanding_ == 0) {
+ Status s = std::move(finish_status_);
+ auto* reactor = reactor_;
+ auto* call = call_.call();
+ this->~ClientCallbackReaderImpl();
+ g_core_codegen_interface->grpc_call_unref(call);
+ reactor->OnDone(s);
+ }
+ }
+
+ void StartCall() override {
+ // This call initiates two batches, plus any backlog, each with a callback
+ // 1. Send initial metadata (unless corked) + recv initial metadata
+ // 2. Any backlog
+ // 3. Recv trailing metadata, on_completion callback
+ // 4. See if the call can finish (if other callbacks were triggered already)
+ started_ = true;
+
+ start_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadInitialMetadataDone(ok);
+ MaybeFinish();
+ },
+ &start_ops_);
+ start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ start_ops_.RecvInitialMetadata(context_);
+ start_ops_.set_core_cq_tag(&start_tag_);
+ call_.PerformOps(&start_ops_);
+
+ // Also set up the read tag so it doesn't have to be set up each time
+ read_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadDone(ok);
+ MaybeFinish();
+ },
+ &read_ops_);
+ read_ops_.set_core_cq_tag(&read_tag_);
+ if (read_ops_at_start_) {
+ call_.PerformOps(&read_ops_);
+ }
+
+ finish_tag_.Set(call_.call(), [this](bool ok) { MaybeFinish(); },
+ &finish_ops_);
+ finish_ops_.ClientRecvStatus(context_, &finish_status_);
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+ call_.PerformOps(&finish_ops_);
+
+ MaybeFinish();
+ }
+
+ void Read(Response* msg) override {
+ read_ops_.RecvMessage(msg);
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&read_ops_);
+ } else {
+ read_ops_at_start_ = true;
+ }
+ }
+
+ private:
+ friend class ClientCallbackReaderFactory<Response>;
+
+ template <class Request>
+ ClientCallbackReaderImpl(
+ Call call, ClientContext* context, Request* request,
+ ::grpc::experimental::ClientReadReactor<Response>* reactor)
+ : context_(context), call_(call), reactor_(reactor) {
+ this->BindReactor(reactor);
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(start_ops_.SendMessage(*request).ok());
+ start_ops_.ClientSendClose();
+ }
+
+ ClientContext* context_;
+ Call call_;
+ ::grpc::experimental::ClientReadReactor<Response>* reactor_;
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose,
+ CallOpRecvInitialMetadata>
+ start_ops_;
+ CallbackWithSuccessTag start_tag_;
+
+ CallOpSet<CallOpClientRecvStatus> finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ Status finish_status_;
+
+ CallOpSet<CallOpRecvMessage<Response>> read_ops_;
+ CallbackWithSuccessTag read_tag_;
+ bool read_ops_at_start_{false};
+
+ // Minimum of 3 callbacks to pre-register for StartCall, start, and finish
+ std::atomic_int callbacks_outstanding_{3};
+ bool started_{false};
+};
+
+template <class Response>
+class ClientCallbackReaderFactory {
+ public:
+ template <class Request>
+ static void Create(
+ ChannelInterface* channel, const ::grpc::internal::RpcMethod& method,
+ ClientContext* context, const Request* request,
+ ::grpc::experimental::ClientReadReactor<Response>* reactor) {
+ Call call = channel->CreateCall(method, context, channel->CallbackCQ());
+
+ g_core_codegen_interface->grpc_call_ref(call.call());
+ new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(ClientCallbackReaderImpl<Response>)))
+ ClientCallbackReaderImpl<Response>(call, context, request, reactor);
+ }
+};
+
+template <class Request>
+class ClientCallbackWriterImpl
+ : public ::grpc::experimental::ClientCallbackWriter<Request> {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(ClientCallbackWriterImpl));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ void MaybeFinish() {
+ if (--callbacks_outstanding_ == 0) {
+ Status s = std::move(finish_status_);
+ auto* reactor = reactor_;
+ auto* call = call_.call();
+ this->~ClientCallbackWriterImpl();
+ g_core_codegen_interface->grpc_call_unref(call);
+ reactor->OnDone(s);
+ }
+ }
+
+ void StartCall() override {
+ // This call initiates two batches, plus any backlog, each with a callback
+ // 1. Send initial metadata (unless corked) + recv initial metadata
+ // 2. Recv trailing metadata, on_completion callback
+ // 3. Any backlog
+ // 4. See if the call can finish (if other callbacks were triggered already)
+ started_ = true;
+
+ start_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadInitialMetadataDone(ok);
+ MaybeFinish();
+ },
+ &start_ops_);
+ if (!start_corked_) {
+ start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ }
+ start_ops_.RecvInitialMetadata(context_);
+ start_ops_.set_core_cq_tag(&start_tag_);
+ call_.PerformOps(&start_ops_);
+
+ // Also set up the read and write tags so that they don't have to be set up
+ // each time
+ write_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWriteDone(ok);
+ MaybeFinish();
+ },
+ &write_ops_);
+ write_ops_.set_core_cq_tag(&write_tag_);
+
+ finish_tag_.Set(call_.call(), [this](bool ok) { MaybeFinish(); },
+ &finish_ops_);
+ finish_ops_.ClientRecvStatus(context_, &finish_status_);
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+ call_.PerformOps(&finish_ops_);
+
+ if (write_ops_at_start_) {
+ call_.PerformOps(&write_ops_);
+ }
+
+ if (writes_done_ops_at_start_) {
+ call_.PerformOps(&writes_done_ops_);
+ }
+
+ MaybeFinish();
+ }
+
+ void Write(const Request* msg, WriteOptions options) override {
+ if (start_corked_) {
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ start_corked_ = false;
+ }
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(write_ops_.SendMessage(*msg).ok());
+
+ if (options.is_last_message()) {
+ options.set_buffer_hint();
+ write_ops_.ClientSendClose();
+ }
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&write_ops_);
+ } else {
+ write_ops_at_start_ = true;
+ }
+ }
+ void WritesDone() override {
+ if (start_corked_) {
+ writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
+ context_->initial_metadata_flags());
+ start_corked_ = false;
+ }
+ writes_done_ops_.ClientSendClose();
+ writes_done_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWritesDoneDone(ok);
+ MaybeFinish();
+ },
+ &writes_done_ops_);
+ writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
+ callbacks_outstanding_++;
+ if (started_) {
+ call_.PerformOps(&writes_done_ops_);
+ } else {
+ writes_done_ops_at_start_ = true;
+ }
+ }
+
+ private:
+ friend class ClientCallbackWriterFactory<Request>;
+
+ template <class Response>
+ ClientCallbackWriterImpl(
+ Call call, ClientContext* context, Response* response,
+ ::grpc::experimental::ClientWriteReactor<Request>* reactor)
+ : context_(context),
+ call_(call),
+ reactor_(reactor),
+ start_corked_(context_->initial_metadata_corked_) {
+ this->BindReactor(reactor);
+ finish_ops_.RecvMessage(response);
+ finish_ops_.AllowNoMessage();
+ }
+
+ ClientContext* context_;
+ Call call_;
+ ::grpc::experimental::ClientWriteReactor<Request>* reactor_;
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpRecvInitialMetadata> start_ops_;
+ CallbackWithSuccessTag start_tag_;
+ bool start_corked_;
+
+ CallOpSet<CallOpGenericRecvMessage, CallOpClientRecvStatus> finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ Status finish_status_;
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
+ write_ops_;
+ CallbackWithSuccessTag write_tag_;
+ bool write_ops_at_start_{false};
+
+ CallOpSet<CallOpSendInitialMetadata, CallOpClientSendClose> writes_done_ops_;
+ CallbackWithSuccessTag writes_done_tag_;
+ bool writes_done_ops_at_start_{false};
+
+ // Minimum of 3 callbacks to pre-register for StartCall, start, and finish
+ std::atomic_int callbacks_outstanding_{3};
+ bool started_{false};
+};
+
+template <class Request>
+class ClientCallbackWriterFactory {
+ public:
+ template <class Response>
+ static void Create(
+ ChannelInterface* channel, const ::grpc::internal::RpcMethod& method,
+ ClientContext* context, Response* response,
+ ::grpc::experimental::ClientWriteReactor<Request>* reactor) {
+ Call call = channel->CreateCall(method, context, channel->CallbackCQ());
+
+ g_core_codegen_interface->grpc_call_ref(call.call());
+ new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(ClientCallbackWriterImpl<Request>)))
+ ClientCallbackWriterImpl<Request>(call, context, response, reactor);
+ }
+};
} // namespace internal
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h
index 24f5c431ce..0a71f3d9b6 100644
--- a/include/grpcpp/impl/codegen/client_context.h
+++ b/include/grpcpp/impl/codegen/client_context.h
@@ -41,10 +41,12 @@
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/slice.h>
#include <grpcpp/impl/codegen/status.h>
@@ -70,6 +72,12 @@ template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
+template <class Request, class Response>
+class ClientCallbackReaderWriterImpl;
+template <class Response>
+class ClientCallbackReaderImpl;
+template <class Request>
+class ClientCallbackWriterImpl;
} // namespace internal
template <class R>
@@ -161,6 +169,8 @@ class InteropClientContextInspector;
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
+/// \warning The ClientContext instance used for creating an rpc must remain
+/// alive and valid for the lifetime of the rpc.
class ClientContext {
public:
ClientContext();
@@ -393,6 +403,12 @@ class ClientContext {
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
+ template <class Request, class Response>
+ friend class ::grpc::internal::ClientCallbackReaderWriterImpl;
+ template <class Response>
+ friend class ::grpc::internal::ClientCallbackReaderImpl;
+ template <class Request>
+ friend class ::grpc::internal::ClientCallbackWriterImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
@@ -402,6 +418,18 @@ class ClientContext {
grpc_call* call() const { return call_; }
void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
+ experimental::ClientRpcInfo* set_client_rpc_info(
+ const char* method, internal::RpcMethod::RpcType type,
+ grpc::ChannelInterface* channel,
+ const std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>&
+ creators,
+ size_t interceptor_pos) {
+ rpc_info_ = experimental::ClientRpcInfo(this, type, method, channel);
+ rpc_info_.RegisterInterceptors(creators, interceptor_pos);
+ return &rpc_info_;
+ }
+
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
(wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
@@ -414,6 +442,8 @@ class ClientContext {
grpc::string authority() { return authority_; }
+ void SendCancelToInterceptors();
+
bool initial_metadata_received_;
bool wait_for_ready_;
bool wait_for_ready_explicitly_set_;
@@ -439,6 +469,8 @@ class ClientContext {
bool initial_metadata_corked_;
grpc::string debug_error_string_;
+
+ experimental::ClientRpcInfo rpc_info_;
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h
index f460c5ac0c..2bae11a251 100644
--- a/include/grpcpp/impl/codegen/client_interceptor.h
+++ b/include/grpcpp/impl/codegen/client_interceptor.h
@@ -19,25 +19,144 @@
#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
+#include <memory>
+#include <vector>
+
#include <grpcpp/impl/codegen/interceptor.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc {
-namespace experimental {
-class ClientInterceptor {
- public:
- virtual ~ClientInterceptor() {}
- virtual void Intercept(InterceptorBatchMethods* methods) = 0;
-};
+class ClientContext;
+class Channel;
+
+namespace internal {
+class InterceptorBatchMethodsImpl;
+}
-class ClientRpcInfo {};
+namespace experimental {
+class ClientRpcInfo;
class ClientInterceptorFactoryInterface {
public:
virtual ~ClientInterceptorFactoryInterface() {}
- virtual ClientInterceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
+ virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
+};
+} // namespace experimental
+
+namespace internal {
+extern experimental::ClientInterceptorFactoryInterface*
+ g_global_client_interceptor_factory;
+}
+
+namespace experimental {
+class ClientRpcInfo {
+ public:
+ // TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN
+ // from the list of possible Types.
+ enum class Type {
+ UNARY,
+ CLIENT_STREAMING,
+ SERVER_STREAMING,
+ BIDI_STREAMING,
+ UNKNOWN // UNKNOWN is not API and will be removed later
+ };
+
+ ~ClientRpcInfo(){};
+
+ ClientRpcInfo(const ClientRpcInfo&) = delete;
+ ClientRpcInfo(ClientRpcInfo&&) = default;
+
+ // Getter methods
+ const char* method() const { return method_; }
+ ChannelInterface* channel() { return channel_; }
+ grpc::ClientContext* client_context() { return ctx_; }
+ Type type() const { return type_; }
+
+ private:
+ static_assert(Type::UNARY ==
+ static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
+ "violated expectation about Type enum");
+ static_assert(Type::CLIENT_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
+ "violated expectation about Type enum");
+ static_assert(Type::SERVER_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
+ "violated expectation about Type enum");
+ static_assert(Type::BIDI_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
+ "violated expectation about Type enum");
+
+ // Default constructor should only be used by ClientContext
+ ClientRpcInfo() = default;
+
+ // Constructor will only be called from ClientContext
+ ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
+ const char* method, grpc::ChannelInterface* channel)
+ : ctx_(ctx),
+ type_(static_cast<Type>(type)),
+ method_(method),
+ channel_(channel) {}
+
+ // Move assignment should only be used by ClientContext
+ // TODO(yashykt): Delete move assignment
+ ClientRpcInfo& operator=(ClientRpcInfo&&) = default;
+
+ // Runs interceptor at pos \a pos.
+ void RunInterceptor(
+ experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
+ GPR_CODEGEN_ASSERT(pos < interceptors_.size());
+ interceptors_[pos]->Intercept(interceptor_methods);
+ }
+
+ void RegisterInterceptors(
+ const std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>& creators,
+ size_t interceptor_pos) {
+ if (interceptor_pos > creators.size()) {
+ // No interceptors to register
+ return;
+ }
+ for (auto it = creators.begin() + interceptor_pos; it != creators.end();
+ ++it) {
+ interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
+ (*it)->CreateClientInterceptor(this)));
+ }
+ if (internal::g_global_client_interceptor_factory != nullptr) {
+ interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
+ internal::g_global_client_interceptor_factory
+ ->CreateClientInterceptor(this)));
+ }
+ }
+
+ grpc::ClientContext* ctx_ = nullptr;
+ // TODO(yashykt): make type_ const once move-assignment is deleted
+ Type type_{Type::UNKNOWN};
+ const char* method_ = nullptr;
+ grpc::ChannelInterface* channel_ = nullptr;
+ std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
+ bool hijacked_ = false;
+ size_t hijacked_interceptor_ = 0;
+
+ friend class internal::InterceptorBatchMethodsImpl;
+ friend class grpc::ClientContext;
};
+// PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL
+// INTERCEPTOR. IF USAGE IS ABSOLUTELY NECESSARY, PLEASE READ THE SAFETY NOTES.
+// Registers a global client interceptor factory object, which is used for all
+// RPCs made in this process. If the argument is nullptr, the global
+// interceptor factory is deregistered. The application is responsible for
+// maintaining the life of the object while gRPC operations are in progress. It
+// is unsafe to try to register/deregister if any gRPC operation is in progress.
+// For safety, it is in the best interests of the developer to register the
+// global interceptor factory once at the start of the process before any gRPC
+// operations have begun. Deregistration is optional since gRPC does not
+// maintain any references to the object.
+void RegisterGlobalClientInterceptorFactory(
+ ClientInterceptorFactoryInterface* factory);
+
} // namespace experimental
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h
index e4e8364e07..5151839412 100644
--- a/include/grpcpp/impl/codegen/client_unary_call.h
+++ b/include/grpcpp/impl/codegen/client_unary_call.h
@@ -61,7 +61,7 @@ class BlockingUnaryCallImpl {
if (!status_.ok()) {
return;
}
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
ops.RecvInitialMetadata(context);
ops.RecvMessage(result);
@@ -69,13 +69,17 @@ class BlockingUnaryCallImpl {
ops.ClientSendClose();
ops.ClientRecvStatus(context, &status_);
call.PerformOps(&ops);
- if (cq.Pluck(&ops)) {
- if (!ops.got_message && status_.ok()) {
- status_ = Status(StatusCode::UNIMPLEMENTED,
- "No message returned for unary request");
- }
- } else {
- GPR_CODEGEN_ASSERT(!status_.ok());
+ cq.Pluck(&ops);
+ // Some of the ops might fail. If the ops fail in the core layer, status
+ // would reflect the error. But, if the ops fail in the C++ layer, the
+ // status would still be the same as the one returned by gRPC Core. This can
+ // happen if deserialization of the message fails.
+ // TODO(yashykt): If deserialization fails, but the status received is OK,
+ // then it might be a good idea to change the status to something better
+ // than StatusCode::UNIMPLEMENTED to reflect this.
+ if (!ops.got_message && status_.ok()) {
+ status_ = Status(StatusCode::UNIMPLEMENTED,
+ "No message returned for unary request");
}
}
Status status() { return status_; }
diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h
index a62d48abe7..fb38788f7d 100644
--- a/include/grpcpp/impl/codegen/completion_queue.h
+++ b/include/grpcpp/impl/codegen/completion_queue.h
@@ -122,8 +122,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// Read from the queue, blocking until an event is available or the queue is
/// shutting down.
///
- /// \param tag[out] Updated to point to the read event's tag.
- /// \param ok[out] true if read a successful event, false otherwise.
+ /// \param tag [out] Updated to point to the read event's tag.
+ /// \param ok [out] true if read a successful event, false otherwise.
///
/// Note that each tag sent to the completion queue (through RPC operations
/// or alarms) will be delivered out of the completion queue by a call to
@@ -178,10 +178,10 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
- /// \param tag[out] Upon sucess, updated to point to the event's tag.
- /// \param ok[out] Upon sucess, true if a successful event, false otherwise
+ /// \param tag [out] Upon sucess, updated to point to the event's tag.
+ /// \param ok [out] Upon sucess, true if a successful event, false otherwise
/// See documentation for CompletionQueue::Next for explanation of ok
- /// \param deadline[in] How long to block in wait for an event.
+ /// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T>
@@ -197,10 +197,11 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
- /// \param F[in] Function to execute before calling AsyncNext on this queue.
- /// \param tag[out] Upon sucess, updated to point to the event's tag.
- /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
- /// \param deadline[in] How long to block in wait for an event.
+ /// \param f [in] Function to execute before calling AsyncNext on this queue.
+ /// \param tag [out] Upon sucess, updated to point to the event's tag.
+ /// \param ok [out] Upon sucess, true if read a regular event, false
+ /// otherwise.
+ /// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T, typename F>
@@ -299,14 +300,16 @@ class CompletionQueue : private GrpcLibraryCodegen {
bool Pluck(internal::CompletionQueueTag* tag) {
auto deadline =
g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
- auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
- cq_, tag, deadline, nullptr);
- bool ok = ev.success != 0;
- void* ignored = tag;
- GPR_CODEGEN_ASSERT(tag->FinalizeResult(&ignored, &ok));
- GPR_CODEGEN_ASSERT(ignored == tag);
- // Ignore mutations by FinalizeResult: Pluck returns the C API status
- return ev.success != 0;
+ while (true) {
+ auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+ cq_, tag, deadline, nullptr);
+ bool ok = ev.success != 0;
+ void* ignored = tag;
+ if (tag->FinalizeResult(&ignored, &ok)) {
+ GPR_CODEGEN_ASSERT(ignored == tag);
+ return ok;
+ }
+ }
}
/// Performs a single polling pluck on \a tag.
@@ -376,13 +379,18 @@ class ServerCompletionQueue : public CompletionQueue {
ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {}
private:
- /// \param is_frequently_polled Informs the GRPC library about whether the
- /// server completion queue would be actively polled (by calling Next() or
- /// AsyncNext()). By default all server completion queues are assumed to be
- /// frequently polled.
- ServerCompletionQueue(grpc_cq_polling_type polling_type)
+ /// \param completion_type indicates whether this is a NEXT or CALLBACK
+ /// completion queue.
+ /// \param polling_type Informs the GRPC library about the type of polling
+ /// allowed on this completion queue. See grpc_cq_polling_type's description
+ /// in grpc_types.h for more details.
+ /// \param shutdown_cb is the shutdown callback used for CALLBACK api queues
+ ServerCompletionQueue(grpc_cq_completion_type completion_type,
+ grpc_cq_polling_type polling_type,
+ grpc_experimental_completion_queue_functor* shutdown_cb)
: CompletionQueue(grpc_completion_queue_attributes{
- GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type, nullptr}),
+ GRPC_CQ_CURRENT_VERSION, completion_type, polling_type,
+ shutdown_cb}),
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;
diff --git a/include/grpcpp/impl/codegen/core_codegen.h b/include/grpcpp/impl/codegen/core_codegen.h
index e9df96bf04..6ef184d01a 100644
--- a/include/grpcpp/impl/codegen/core_codegen.h
+++ b/include/grpcpp/impl/codegen/core_codegen.h
@@ -63,6 +63,9 @@ class CoreCodegen final : public CoreCodegenInterface {
void gpr_cv_signal(gpr_cv* cv) override;
void gpr_cv_broadcast(gpr_cv* cv) override;
+ grpc_call_error grpc_call_start_batch(grpc_call* call, const grpc_op* ops,
+ size_t nops, void* tag,
+ void* reserved) override;
grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
diff --git a/include/grpcpp/impl/codegen/core_codegen_interface.h b/include/grpcpp/impl/codegen/core_codegen_interface.h
index 1167a188a2..20a5b3300c 100644
--- a/include/grpcpp/impl/codegen/core_codegen_interface.h
+++ b/include/grpcpp/impl/codegen/core_codegen_interface.h
@@ -100,6 +100,9 @@ class CoreCodegenInterface {
virtual grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*,
size_t)) = 0;
+ virtual grpc_call_error grpc_call_start_batch(grpc_call* call,
+ const grpc_op* ops, size_t nops,
+ void* tag, void* reserved) = 0;
virtual grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
@@ -142,6 +145,15 @@ extern CoreCodegenInterface* g_core_codegen_interface;
} \
} while (0)
+/// Codegen specific version of \a GPR_DEBUG_ASSERT.
+#ifndef NDEBUG
+#define GPR_CODEGEN_DEBUG_ASSERT(x) GPR_CODEGEN_ASSERT(x)
+#else
+#define GPR_CODEGEN_DEBUG_ASSERT(x) \
+ do { \
+ } while (0)
+#endif
+
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
diff --git a/include/grpcpp/impl/codegen/intercepted_channel.h b/include/grpcpp/impl/codegen/intercepted_channel.h
new file mode 100644
index 0000000000..5255a6d147
--- /dev/null
+++ b/include/grpcpp/impl/codegen/intercepted_channel.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
+#define GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
+
+#include <grpcpp/impl/codegen/channel_interface.h>
+
+namespace grpc {
+
+namespace internal {
+
+class InterceptorBatchMethodsImpl;
+
+/// An InterceptedChannel is available to client Interceptors. An
+/// InterceptedChannel is unique to an interceptor, and when an RPC is started
+/// on this channel, only those interceptors that come after this interceptor
+/// see the RPC.
+class InterceptedChannel : public ChannelInterface {
+ public:
+ virtual ~InterceptedChannel() { channel_ = nullptr; }
+
+ /// Get the current channel state. If the channel is in IDLE and
+ /// \a try_to_connect is set to true, try to connect.
+ grpc_connectivity_state GetState(bool try_to_connect) override {
+ return channel_->GetState(try_to_connect);
+ }
+
+ private:
+ InterceptedChannel(ChannelInterface* channel, size_t pos)
+ : channel_(channel), interceptor_pos_(pos) {}
+
+ Call CreateCall(const RpcMethod& method, ClientContext* context,
+ CompletionQueue* cq) override {
+ return channel_->CreateCallInternal(method, context, cq, interceptor_pos_);
+ }
+
+ void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override {
+ return channel_->PerformOpsOnCall(ops, call);
+ }
+ void* RegisterMethod(const char* method) override {
+ return channel_->RegisterMethod(method);
+ }
+
+ void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
+ gpr_timespec deadline, CompletionQueue* cq,
+ void* tag) override {
+ return channel_->NotifyOnStateChangeImpl(last_observed, deadline, cq, tag);
+ }
+ bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
+ gpr_timespec deadline) override {
+ return channel_->WaitForStateChangeImpl(last_observed, deadline);
+ }
+
+ CompletionQueue* CallbackCQ() override { return channel_->CallbackCQ(); }
+
+ ChannelInterface* channel_;
+ size_t interceptor_pos_;
+
+ friend class InterceptorBatchMethodsImpl;
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
diff --git a/include/grpcpp/impl/codegen/interceptor.h b/include/grpcpp/impl/codegen/interceptor.h
index 6402a3a946..e449e44a23 100644
--- a/include/grpcpp/impl/codegen/interceptor.h
+++ b/include/grpcpp/impl/codegen/interceptor.h
@@ -19,7 +19,17 @@
#ifndef GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/metadata_map.h>
+
namespace grpc {
+
+class ChannelInterface;
+class Status;
+
namespace experimental {
class InterceptedMessage {
public:
@@ -35,6 +45,7 @@ enum class InterceptionHookPoints {
PRE_SEND_INITIAL_METADATA,
PRE_SEND_MESSAGE,
PRE_SEND_STATUS /* server only */,
+ PRE_SEND_CLOSE /* client only */,
/* The following three are for hijacked clients only and can only be
registered by the global interceptor */
PRE_RECV_INITIAL_METADATA,
@@ -45,22 +56,77 @@ enum class InterceptionHookPoints {
POST_RECV_MESSAGE,
POST_RECV_STATUS /* client only */,
POST_RECV_CLOSE /* server only */,
+ /* This is a special hook point available to both clients and servers when
+ TryCancel() is performed.
+ - No other hook points will be present along with this.
+ - It is illegal for an interceptor to block/delay this operation.
+ - ALL interceptors see this hook point irrespective of whether the RPC was
+ hijacked or not. */
+ PRE_SEND_CANCEL,
NUM_INTERCEPTION_HOOKS
};
class InterceptorBatchMethods {
public:
- virtual ~InterceptorBatchMethods();
+ virtual ~InterceptorBatchMethods(){};
// Queries to check whether the current batch has an interception hook point
// of type \a type
virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0;
// Calling this will signal that the interceptor is done intercepting the
- // current batch of the RPC
+ // current batch of the RPC.
+ // Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
+ // from the Intercept method does the job of continuing the RPC in this case.
virtual void Proceed() = 0;
// Calling this indicates that the interceptor has hijacked the RPC (only
// valid if the batch contains send_initial_metadata on the client side)
virtual void Hijack() = 0;
+
+ // Returns a modifable ByteBuffer holding serialized form of the message to be
+ // sent
+ virtual ByteBuffer* GetSendMessage() = 0;
+
+ // Returns a modifiable multimap of the initial metadata to be sent
+ virtual std::multimap<grpc::string, grpc::string>*
+ GetSendInitialMetadata() = 0;
+
+ // Returns the status to be sent
+ virtual Status GetSendStatus() = 0;
+
+ // Modifies the status with \a status
+ virtual void ModifySendStatus(const Status& status) = 0;
+
+ // Returns a modifiable multimap of the trailing metadata to be sent
+ virtual std::multimap<grpc::string, grpc::string>*
+ GetSendTrailingMetadata() = 0;
+
+ // Returns a pointer to the modifiable received message. Note that the message
+ // is already deserialized
+ virtual void* GetRecvMessage() = 0;
+
+ // Returns a modifiable multimap of the received initial metadata
+ virtual std::multimap<grpc::string_ref, grpc::string_ref>*
+ GetRecvInitialMetadata() = 0;
+
+ // Returns a modifiable view of the received status
+ virtual Status* GetRecvStatus() = 0;
+
+ // Returns a modifiable multimap of the received trailing metadata
+ virtual std::multimap<grpc::string_ref, grpc::string_ref>*
+ GetRecvTrailingMetadata() = 0;
+
+ // Gets an intercepted channel. When a call is started on this interceptor,
+ // only interceptors after the current interceptor are created from the
+ // factory objects registered with the channel.
+ virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0;
};
+
+class Interceptor {
+ public:
+ virtual ~Interceptor() {}
+
+ virtual void Intercept(InterceptorBatchMethods* methods) = 0;
+};
+
} // namespace experimental
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/interceptor_common.h b/include/grpcpp/impl/codegen/interceptor_common.h
new file mode 100644
index 0000000000..d0aa23cb0a
--- /dev/null
+++ b/include/grpcpp/impl/codegen/interceptor_common.h
@@ -0,0 +1,458 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
+#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
+
+#include <array>
+#include <functional>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_op_set_interface.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
+#include <grpcpp/impl/codegen/intercepted_channel.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+namespace internal {
+
+class InterceptorBatchMethodsImpl
+ : public experimental::InterceptorBatchMethods {
+ public:
+ InterceptorBatchMethodsImpl() {
+ for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
+ i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
+ i = static_cast<experimental::InterceptionHookPoints>(
+ static_cast<size_t>(i) + 1)) {
+ hooks_[static_cast<size_t>(i)] = false;
+ }
+ }
+
+ ~InterceptorBatchMethodsImpl() {}
+
+ bool QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints type) override {
+ return hooks_[static_cast<size_t>(type)];
+ }
+
+ void Proceed() override {
+ if (call_->client_rpc_info() != nullptr) {
+ return ProceedClient();
+ }
+ GPR_CODEGEN_ASSERT(call_->server_rpc_info() != nullptr);
+ ProceedServer();
+ }
+
+ void Hijack() override {
+ // Only the client can hijack when sending down initial metadata
+ GPR_CODEGEN_ASSERT(!reverse_ && ops_ != nullptr &&
+ call_->client_rpc_info() != nullptr);
+ // It is illegal to call Hijack twice
+ GPR_CODEGEN_ASSERT(!ran_hijacking_interceptor_);
+ auto* rpc_info = call_->client_rpc_info();
+ rpc_info->hijacked_ = true;
+ rpc_info->hijacked_interceptor_ = current_interceptor_index_;
+ ClearHookPoints();
+ ops_->SetHijackingState();
+ ran_hijacking_interceptor_ = true;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void AddInterceptionHookPoint(experimental::InterceptionHookPoints type) {
+ hooks_[static_cast<size_t>(type)] = true;
+ }
+
+ ByteBuffer* GetSendMessage() override { return send_message_; }
+
+ std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
+ return send_initial_metadata_;
+ }
+
+ Status GetSendStatus() override {
+ return Status(static_cast<StatusCode>(*code_), *error_message_,
+ *error_details_);
+ }
+
+ void ModifySendStatus(const Status& status) override {
+ *code_ = static_cast<grpc_status_code>(status.error_code());
+ *error_details_ = status.error_details();
+ *error_message_ = status.error_message();
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
+ override {
+ return send_trailing_metadata_;
+ }
+
+ void* GetRecvMessage() override { return recv_message_; }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
+ override {
+ return recv_initial_metadata_->map();
+ }
+
+ Status* GetRecvStatus() override { return recv_status_; }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
+ override {
+ return recv_trailing_metadata_->map();
+ }
+
+ void SetSendMessage(ByteBuffer* buf) { send_message_ = buf; }
+
+ void SetSendInitialMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ send_initial_metadata_ = metadata;
+ }
+
+ void SetSendStatus(grpc_status_code* code, grpc::string* error_details,
+ grpc::string* error_message) {
+ code_ = code;
+ error_details_ = error_details;
+ error_message_ = error_message;
+ }
+
+ void SetSendTrailingMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ send_trailing_metadata_ = metadata;
+ }
+
+ void SetRecvMessage(void* message) { recv_message_ = message; }
+
+ void SetRecvInitialMetadata(MetadataMap* map) {
+ recv_initial_metadata_ = map;
+ }
+
+ void SetRecvStatus(Status* status) { recv_status_ = status; }
+
+ void SetRecvTrailingMetadata(MetadataMap* map) {
+ recv_trailing_metadata_ = map;
+ }
+
+ std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
+ auto* info = call_->client_rpc_info();
+ if (info == nullptr) {
+ return std::unique_ptr<ChannelInterface>(nullptr);
+ }
+ // The intercepted channel starts from the interceptor just after the
+ // current interceptor
+ return std::unique_ptr<ChannelInterface>(new InterceptedChannel(
+ info->channel(), current_interceptor_index_ + 1));
+ }
+
+ // Clears all state
+ void ClearState() {
+ reverse_ = false;
+ ran_hijacking_interceptor_ = false;
+ ClearHookPoints();
+ }
+
+ // Prepares for Post_recv operations
+ void SetReverse() {
+ reverse_ = true;
+ ran_hijacking_interceptor_ = false;
+ ClearHookPoints();
+ }
+
+ // This needs to be set before interceptors are run
+ void SetCall(Call* call) { call_ = call; }
+
+ // This needs to be set before interceptors are run using RunInterceptors().
+ // Alternatively, RunInterceptors(std::function<void(void)> f) can be used.
+ void SetCallOpSetInterface(CallOpSetInterface* ops) { ops_ = ops; }
+
+ // Returns true if no interceptors are run. This should be used only by
+ // subclasses of CallOpSetInterface. SetCall and SetCallOpSetInterface should
+ // have been called before this. After all the interceptors are done running,
+ // either ContinueFillOpsAfterInterception or
+ // ContinueFinalizeOpsAfterInterception will be called. Note that neither of
+ // them is invoked if there were no interceptors registered.
+ bool RunInterceptors() {
+ GPR_CODEGEN_ASSERT(ops_);
+ auto* client_rpc_info = call_->client_rpc_info();
+ if (client_rpc_info != nullptr) {
+ if (client_rpc_info->interceptors_.size() == 0) {
+ return true;
+ } else {
+ RunClientInterceptors();
+ return false;
+ }
+ }
+
+ auto* server_rpc_info = call_->server_rpc_info();
+ if (server_rpc_info == nullptr ||
+ server_rpc_info->interceptors_.size() == 0) {
+ return true;
+ }
+ RunServerInterceptors();
+ return false;
+ }
+
+ // Returns true if no interceptors are run. Returns false otherwise if there
+ // are interceptors registered. After the interceptors are done running \a f
+ // will be invoked. This is to be used only by BaseAsyncRequest and
+ // SyncRequest.
+ bool RunInterceptors(std::function<void(void)> f) {
+ // This is used only by the server for initial call request
+ GPR_CODEGEN_ASSERT(reverse_ == true);
+ GPR_CODEGEN_ASSERT(call_->client_rpc_info() == nullptr);
+ auto* server_rpc_info = call_->server_rpc_info();
+ if (server_rpc_info == nullptr ||
+ server_rpc_info->interceptors_.size() == 0) {
+ return true;
+ }
+ callback_ = std::move(f);
+ RunServerInterceptors();
+ return false;
+ }
+
+ private:
+ void RunClientInterceptors() {
+ auto* rpc_info = call_->client_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_ = 0;
+ } else {
+ if (rpc_info->hijacked_) {
+ current_interceptor_index_ = rpc_info->hijacked_interceptor_;
+ } else {
+ current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
+ }
+ }
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void RunServerInterceptors() {
+ auto* rpc_info = call_->server_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_ = 0;
+ } else {
+ current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
+ }
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void ProceedClient() {
+ auto* rpc_info = call_->client_rpc_info();
+ if (rpc_info->hijacked_ && !reverse_ &&
+ current_interceptor_index_ == rpc_info->hijacked_interceptor_ &&
+ !ran_hijacking_interceptor_) {
+ // We now need to provide hijacked recv ops to this interceptor
+ ClearHookPoints();
+ ops_->SetHijackingState();
+ ran_hijacking_interceptor_ = true;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ return;
+ }
+ if (!reverse_) {
+ current_interceptor_index_++;
+ // We are going down the stack of interceptors
+ if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
+ if (rpc_info->hijacked_ &&
+ current_interceptor_index_ > rpc_info->hijacked_interceptor_) {
+ // This is a hijacked RPC and we are done with hijacking
+ ops_->ContinueFillOpsAfterInterception();
+ } else {
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+ } else {
+ // we are done running all the interceptors without any hijacking
+ ops_->ContinueFillOpsAfterInterception();
+ }
+ } else {
+ // We are going up the stack of interceptors
+ if (current_interceptor_index_ > 0) {
+ // Continue running interceptors
+ current_interceptor_index_--;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else {
+ // we are done running all the interceptors without any hijacking
+ ops_->ContinueFinalizeResultAfterInterception();
+ }
+ }
+ }
+
+ void ProceedServer() {
+ auto* rpc_info = call_->server_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_++;
+ if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
+ return rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else if (ops_) {
+ return ops_->ContinueFillOpsAfterInterception();
+ }
+ } else {
+ // We are going up the stack of interceptors
+ if (current_interceptor_index_ > 0) {
+ // Continue running interceptors
+ current_interceptor_index_--;
+ return rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else if (ops_) {
+ return ops_->ContinueFinalizeResultAfterInterception();
+ }
+ }
+ GPR_CODEGEN_ASSERT(callback_);
+ callback_();
+ }
+
+ void ClearHookPoints() {
+ for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
+ i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
+ i = static_cast<experimental::InterceptionHookPoints>(
+ static_cast<size_t>(i) + 1)) {
+ hooks_[static_cast<size_t>(i)] = false;
+ }
+ }
+
+ std::array<bool,
+ static_cast<size_t>(
+ experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS)>
+ hooks_;
+
+ size_t current_interceptor_index_ = 0; // Current iterator
+ bool reverse_ = false;
+ bool ran_hijacking_interceptor_ = false;
+ Call* call_ = nullptr; // The Call object is present along with CallOpSet
+ // object/callback
+ CallOpSetInterface* ops_ = nullptr;
+ std::function<void(void)> callback_;
+
+ ByteBuffer* send_message_ = nullptr;
+
+ std::multimap<grpc::string, grpc::string>* send_initial_metadata_;
+
+ grpc_status_code* code_ = nullptr;
+ grpc::string* error_details_ = nullptr;
+ grpc::string* error_message_ = nullptr;
+ Status send_status_;
+
+ std::multimap<grpc::string, grpc::string>* send_trailing_metadata_ = nullptr;
+
+ void* recv_message_ = nullptr;
+
+ MetadataMap* recv_initial_metadata_ = nullptr;
+
+ Status* recv_status_ = nullptr;
+
+ MetadataMap* recv_trailing_metadata_ = nullptr;
+};
+
+// A special implementation of InterceptorBatchMethods to send a Cancel
+// notification down the interceptor stack
+class CancelInterceptorBatchMethods
+ : public experimental::InterceptorBatchMethods {
+ public:
+ bool QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints type) override {
+ if (type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void Proceed() override {
+ // This is a no-op. For actual continuation of the RPC simply needs to
+ // return from the Intercept method
+ }
+
+ void Hijack() override {
+ // Only the client can hijack when sending down initial metadata
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call Hijack on a method which has a "
+ "Cancel notification");
+ }
+
+ ByteBuffer* GetSendMessage() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendMessage on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendInitialMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ Status GetSendStatus() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendStatus on a method which "
+ "has a Cancel notification");
+ return Status();
+ }
+
+ void ModifySendStatus(const Status& status) override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call ModifySendStatus on a method "
+ "which has a Cancel notification");
+ return;
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendTrailingMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ void* GetRecvMessage() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvMessage on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvInitialMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ Status* GetRecvStatus() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvStatus on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvTrailingMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetInterceptedChannel on a "
+ "method which has a Cancel notification");
+ return std::unique_ptr<ChannelInterface>(nullptr);
+ }
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
diff --git a/include/grpcpp/impl/codegen/metadata_map.h b/include/grpcpp/impl/codegen/metadata_map.h
index 5e062a50f8..9cec54d9f0 100644
--- a/include/grpcpp/impl/codegen/metadata_map.h
+++ b/include/grpcpp/impl/codegen/metadata_map.h
@@ -19,6 +19,8 @@
#ifndef GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
#define GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
+#include <map>
+
#include <grpc/impl/codegen/log.h>
#include <grpcpp/impl/codegen/slice.h>
@@ -30,11 +32,9 @@ const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
class MetadataMap {
public:
- MetadataMap() { memset(&arr_, 0, sizeof(arr_)); }
+ MetadataMap() { Setup(); }
- ~MetadataMap() {
- g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
- }
+ ~MetadataMap() { Destroy(); }
grpc::string GetBinaryErrorDetails() {
// if filled_, extract from the multimap for O(log(n))
@@ -69,11 +69,24 @@ class MetadataMap {
}
grpc_metadata_array* arr() { return &arr_; }
+ void Reset() {
+ filled_ = false;
+ map_.clear();
+ Destroy();
+ Setup();
+ }
+
private:
bool filled_ = false;
grpc_metadata_array arr_;
std::multimap<grpc::string_ref, grpc::string_ref> map_;
+ void Destroy() {
+ g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
+ }
+
+ void Setup() { memset(&arr_, 0, sizeof(arr_)); }
+
void FillMap() {
if (filled_) return;
filled_ = true;
diff --git a/include/grpcpp/impl/codegen/method_handler_impl.h b/include/grpcpp/impl/codegen/method_handler_impl.h
index 53117f941b..dd53f975f6 100644
--- a/include/grpcpp/impl/codegen/method_handler_impl.h
+++ b/include/grpcpp/impl/codegen/method_handler_impl.h
@@ -59,21 +59,21 @@ class RpcMethodHandler : public MethodHandler {
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
- RequestType req;
- Status status = SerializationTraits<RequestType>::Deserialize(
- param.request.bbuf_ptr(), &req);
ResponseType rsp;
+ Status status = param.status;
if (status.ok()) {
- status = CatchingFunctionHandler([this, &param, &req, &rsp] {
- return func_(service_, param.server_context, &req, &rsp);
+ status = CatchingFunctionHandler([this, &param, &rsp] {
+ return func_(service_, param.server_context,
+ static_cast<RequestType*>(param.request), &rsp);
});
+ static_cast<RequestType*>(param.request)->~RequestType();
}
GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpServerSendStatus>
ops;
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -81,11 +81,26 @@ class RpcMethodHandler : public MethodHandler {
if (status.ok()) {
status = ops.SendMessage(rsp);
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ ByteBuffer buf;
+ buf.set_buffer(req);
+ auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call, sizeof(RequestType))) RequestType();
+ *status = SerializationTraits<RequestType>::Deserialize(&buf, request);
+ buf.Release();
+ if (status->ok()) {
+ return request;
+ }
+ request->~RequestType();
+ return nullptr;
+ }
+
private:
/// Application provided rpc handler function.
std::function<Status(ServiceType*, ServerContext*, const RequestType*,
@@ -117,7 +132,7 @@ class ClientStreamingHandler : public MethodHandler {
CallOpServerSendStatus>
ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -126,7 +141,7 @@ class ClientStreamingHandler : public MethodHandler {
if (status.ok()) {
status = ops.SendMessage(rsp);
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
@@ -150,26 +165,25 @@ class ServerStreamingHandler : public MethodHandler {
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
- RequestType req;
- Status status = SerializationTraits<RequestType>::Deserialize(
- param.request.bbuf_ptr(), &req);
-
+ Status status = param.status;
if (status.ok()) {
ServerWriter<ResponseType> writer(param.call, param.server_context);
- status = CatchingFunctionHandler([this, &param, &req, &writer] {
- return func_(service_, param.server_context, &req, &writer);
+ status = CatchingFunctionHandler([this, &param, &writer] {
+ return func_(service_, param.server_context,
+ static_cast<RequestType*>(param.request), &writer);
});
+ static_cast<RequestType*>(param.request)->~RequestType();
}
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
@@ -177,6 +191,21 @@ class ServerStreamingHandler : public MethodHandler {
param.call->cq()->Pluck(&ops);
}
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ ByteBuffer buf;
+ buf.set_buffer(req);
+ auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call, sizeof(RequestType))) RequestType();
+ *status = SerializationTraits<RequestType>::Deserialize(&buf, request);
+ buf.Release();
+ if (status->ok()) {
+ return request;
+ }
+ request->~RequestType();
+ return nullptr;
+ }
+
private:
std::function<Status(ServiceType*, ServerContext*, const RequestType*,
ServerWriter<ResponseType>*)>
@@ -206,7 +235,7 @@ class TemplatedBidiStreamingHandler : public MethodHandler {
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -218,7 +247,7 @@ class TemplatedBidiStreamingHandler : public MethodHandler {
"Service did not provide response message");
}
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
@@ -281,14 +310,14 @@ class ErrorMethodHandler : public MethodHandler {
static void FillOps(ServerContext* context, T* ops) {
Status status(code, "");
if (!context->sent_initial_metadata_) {
- ops->SendInitialMetadata(context->initial_metadata_,
+ ops->SendInitialMetadata(&context->initial_metadata_,
context->initial_metadata_flags());
if (context->compression_level_set()) {
ops->set_compression_level(context->compression_level());
}
context->sent_initial_metadata_ = true;
}
- ops->ServerSendStatus(context->trailing_metadata_, status);
+ ops->ServerSendStatus(&context->trailing_metadata_, status);
}
void RunHandler(const HandlerParameter& param) final {
@@ -296,11 +325,15 @@ class ErrorMethodHandler : public MethodHandler {
FillOps(param.server_context, &ops);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
- // We also have to destroy any request payload in the handler parameter
- ByteBuffer* payload = param.request.bbuf_ptr();
- if (payload != nullptr) {
- payload->Clear();
+ }
+
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ // We have to destroy any request payload
+ if (req != nullptr) {
+ g_core_codegen_interface->grpc_byte_buffer_destroy(req);
}
+ return nullptr;
}
};
diff --git a/include/grpcpp/impl/codegen/rpc_service_method.h b/include/grpcpp/impl/codegen/rpc_service_method.h
index 5cf88e216f..f465c5fc2f 100644
--- a/include/grpcpp/impl/codegen/rpc_service_method.h
+++ b/include/grpcpp/impl/codegen/rpc_service_method.h
@@ -40,17 +40,41 @@ class MethodHandler {
public:
virtual ~MethodHandler() {}
struct HandlerParameter {
- HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req)
- : call(c), server_context(context) {
- request.set_buffer(req);
- }
- ~HandlerParameter() { request.Release(); }
+ /// Constructor for HandlerParameter
+ ///
+ /// \param c : the gRPC Call structure for this server call
+ /// \param context : the ServerContext structure for this server call
+ /// \param req : the request payload, if appropriate for this RPC
+ /// \param req_status : the request status after any interceptors have run
+ /// \param rpc_requester : used only by the callback API. It is a function
+ /// called by the RPC Controller to request another RPC (and also
+ /// to set up the state required to make that request possible)
+ HandlerParameter(Call* c, ServerContext* context, void* req,
+ Status req_status, std::function<void()> requester)
+ : call(c),
+ server_context(context),
+ request(req),
+ status(req_status),
+ call_requester(std::move(requester)) {}
+ ~HandlerParameter() {}
Call* call;
ServerContext* server_context;
- // Handler required to destroy these contents
- ByteBuffer request;
+ void* request;
+ Status status;
+ std::function<void()> call_requester;
};
virtual void RunHandler(const HandlerParameter& param) = 0;
+
+ /* Returns a pointer to the deserialized request. \a status reflects the
+ result of deserialization. This pointer and the status should be filled in
+ a HandlerParameter and passed to RunHandler. It is illegal to access the
+ pointer after calling RunHandler. Ownership of the deserialized request is
+ retained by the handler. Returns nullptr if deserialization failed. */
+ virtual void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) {
+ GPR_CODEGEN_ASSERT(req == nullptr);
+ return nullptr;
+ }
};
/// Server side rpc method class
@@ -61,25 +85,29 @@ class RpcServiceMethod : public RpcMethod {
MethodHandler* handler)
: RpcMethod(name, type),
server_tag_(nullptr),
- async_type_(AsyncType::UNSET),
+ api_type_(ApiType::SYNC),
handler_(handler) {}
- enum class AsyncType {
- UNSET,
+ enum class ApiType {
+ SYNC,
ASYNC,
RAW,
+ CALL_BACK, // not CALLBACK because that is reserved in Windows
+ RAW_CALL_BACK,
};
void set_server_tag(void* tag) { server_tag_ = tag; }
void* server_tag() const { return server_tag_; }
/// if MethodHandler is nullptr, then this is an async method
MethodHandler* handler() const { return handler_.get(); }
+ ApiType api_type() const { return api_type_; }
void SetHandler(MethodHandler* handler) { handler_.reset(handler); }
- void SetServerAsyncType(RpcServiceMethod::AsyncType type) {
- if (async_type_ == AsyncType::UNSET) {
+ void SetServerApiType(RpcServiceMethod::ApiType type) {
+ if ((api_type_ == ApiType::SYNC) &&
+ (type == ApiType::ASYNC || type == ApiType::RAW)) {
// this marks this method as async
handler_.reset();
- } else {
+ } else if (api_type_ != ApiType::SYNC) {
// this is not an error condition, as it allows users to declare a server
// like WithRawMethod_foo<AsyncService>. However since it
// overwrites behavior, it should be logged.
@@ -88,24 +116,28 @@ class RpcServiceMethod : public RpcMethod {
"You are marking method %s as '%s', even though it was "
"previously marked '%s'. This behavior will overwrite the original "
"behavior. If you expected this then ignore this message.",
- name(), TypeToString(async_type_), TypeToString(type));
+ name(), TypeToString(api_type_), TypeToString(type));
}
- async_type_ = type;
+ api_type_ = type;
}
private:
void* server_tag_;
- AsyncType async_type_;
+ ApiType api_type_;
std::unique_ptr<MethodHandler> handler_;
- const char* TypeToString(RpcServiceMethod::AsyncType type) {
+ const char* TypeToString(RpcServiceMethod::ApiType type) {
switch (type) {
- case AsyncType::UNSET:
- return "unset";
- case AsyncType::ASYNC:
+ case ApiType::SYNC:
+ return "sync";
+ case ApiType::ASYNC:
return "async";
- case AsyncType::RAW:
+ case ApiType::RAW:
return "raw";
+ case ApiType::CALL_BACK:
+ return "callback";
+ case ApiType::RAW_CALL_BACK:
+ return "raw_callback";
default:
GPR_UNREACHABLE_CODE(return "unknown");
}
diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h
new file mode 100644
index 0000000000..1854f6ef2f
--- /dev/null
+++ b/include/grpcpp/impl/codegen/server_callback.h
@@ -0,0 +1,890 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
+
+#include <atomic>
+#include <functional>
+#include <type_traits>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_op_set.h>
+#include <grpcpp/impl/codegen/callback_common.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/server_context.h>
+#include <grpcpp/impl/codegen/server_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+// Declare base class of all reactors as internal
+namespace internal {
+
+class ServerReactor {
+ public:
+ virtual ~ServerReactor() = default;
+ virtual void OnDone() {}
+ virtual void OnCancel() {}
+};
+
+} // namespace internal
+
+namespace experimental {
+
+// Forward declarations
+template <class Request, class Response>
+class ServerReadReactor;
+template <class Request, class Response>
+class ServerWriteReactor;
+template <class Request, class Response>
+class ServerBidiReactor;
+
+// For unary RPCs, the exposed controller class is only an interface
+// and the actual implementation is an internal class.
+class ServerCallbackRpcController {
+ public:
+ virtual ~ServerCallbackRpcController() = default;
+
+ // The method handler must call this function when it is done so that
+ // the library knows to free its resources
+ virtual void Finish(Status s) = 0;
+
+ // Allow the method handler to push out the initial metadata before
+ // the response and status are ready
+ virtual void SendInitialMetadata(std::function<void(bool)>) = 0;
+};
+
+// NOTE: The actual streaming object classes are provided
+// as API only to support mocking. There are no implementations of
+// these class interfaces in the API.
+template <class Request>
+class ServerCallbackReader {
+ public:
+ virtual ~ServerCallbackReader() {}
+ virtual void Finish(Status s) = 0;
+ virtual void SendInitialMetadata() = 0;
+ virtual void Read(Request* msg) = 0;
+
+ protected:
+ template <class Response>
+ void BindReactor(ServerReadReactor<Request, Response>* reactor) {
+ reactor->BindReader(this);
+ }
+};
+
+template <class Response>
+class ServerCallbackWriter {
+ public:
+ virtual ~ServerCallbackWriter() {}
+
+ virtual void Finish(Status s) = 0;
+ virtual void SendInitialMetadata() = 0;
+ virtual void Write(const Response* msg, WriteOptions options) = 0;
+ virtual void WriteAndFinish(const Response* msg, WriteOptions options,
+ Status s) {
+ // Default implementation that can/should be overridden
+ Write(msg, std::move(options));
+ Finish(std::move(s));
+ };
+
+ protected:
+ template <class Request>
+ void BindReactor(ServerWriteReactor<Request, Response>* reactor) {
+ reactor->BindWriter(this);
+ }
+};
+
+template <class Request, class Response>
+class ServerCallbackReaderWriter {
+ public:
+ virtual ~ServerCallbackReaderWriter() {}
+
+ virtual void Finish(Status s) = 0;
+ virtual void SendInitialMetadata() = 0;
+ virtual void Read(Request* msg) = 0;
+ virtual void Write(const Response* msg, WriteOptions options) = 0;
+ virtual void WriteAndFinish(const Response* msg, WriteOptions options,
+ Status s) {
+ // Default implementation that can/should be overridden
+ Write(msg, std::move(options));
+ Finish(std::move(s));
+ };
+
+ protected:
+ void BindReactor(ServerBidiReactor<Request, Response>* reactor) {
+ reactor->BindStream(this);
+ }
+};
+
+// The following classes are reactors that are to be implemented
+// by the user, returned as the result of the method handler for
+// a callback method, and activated by the call to OnStarted
+template <class Request, class Response>
+class ServerBidiReactor : public internal::ServerReactor {
+ public:
+ ~ServerBidiReactor() = default;
+ virtual void OnStarted(ServerContext*) {}
+ virtual void OnSendInitialMetadataDone(bool ok) {}
+ virtual void OnReadDone(bool ok) {}
+ virtual void OnWriteDone(bool ok) {}
+
+ void StartSendInitialMetadata() { stream_->SendInitialMetadata(); }
+ void StartRead(Request* msg) { stream_->Read(msg); }
+ void StartWrite(const Response* msg) { StartWrite(msg, WriteOptions()); }
+ void StartWrite(const Response* msg, WriteOptions options) {
+ stream_->Write(msg, std::move(options));
+ }
+ void StartWriteAndFinish(const Response* msg, WriteOptions options,
+ Status s) {
+ stream_->WriteAndFinish(msg, std::move(options), std::move(s));
+ }
+ void StartWriteLast(const Response* msg, WriteOptions options) {
+ StartWrite(msg, std::move(options.set_last_message()));
+ }
+ void Finish(Status s) { stream_->Finish(std::move(s)); }
+
+ private:
+ friend class ServerCallbackReaderWriter<Request, Response>;
+ void BindStream(ServerCallbackReaderWriter<Request, Response>* stream) {
+ stream_ = stream;
+ }
+
+ ServerCallbackReaderWriter<Request, Response>* stream_;
+};
+
+template <class Request, class Response>
+class ServerReadReactor : public internal::ServerReactor {
+ public:
+ ~ServerReadReactor() = default;
+ virtual void OnStarted(ServerContext*, Response* resp) {}
+ virtual void OnSendInitialMetadataDone(bool ok) {}
+ virtual void OnReadDone(bool ok) {}
+
+ void StartSendInitialMetadata() { reader_->SendInitialMetadata(); }
+ void StartRead(Request* msg) { reader_->Read(msg); }
+ void Finish(Status s) { reader_->Finish(std::move(s)); }
+
+ private:
+ friend class ServerCallbackReader<Request>;
+ void BindReader(ServerCallbackReader<Request>* reader) { reader_ = reader; }
+
+ ServerCallbackReader<Request>* reader_;
+};
+
+template <class Request, class Response>
+class ServerWriteReactor : public internal::ServerReactor {
+ public:
+ ~ServerWriteReactor() = default;
+ virtual void OnStarted(ServerContext*, const Request* req) {}
+ virtual void OnSendInitialMetadataDone(bool ok) {}
+ virtual void OnWriteDone(bool ok) {}
+
+ void StartSendInitialMetadata() { writer_->SendInitialMetadata(); }
+ void StartWrite(const Response* msg) { StartWrite(msg, WriteOptions()); }
+ void StartWrite(const Response* msg, WriteOptions options) {
+ writer_->Write(msg, std::move(options));
+ }
+ void StartWriteAndFinish(const Response* msg, WriteOptions options,
+ Status s) {
+ writer_->WriteAndFinish(msg, std::move(options), std::move(s));
+ }
+ void StartWriteLast(const Response* msg, WriteOptions options) {
+ StartWrite(msg, std::move(options.set_last_message()));
+ }
+ void Finish(Status s) { writer_->Finish(std::move(s)); }
+
+ private:
+ friend class ServerCallbackWriter<Response>;
+ void BindWriter(ServerCallbackWriter<Response>* writer) { writer_ = writer; }
+
+ ServerCallbackWriter<Response>* writer_;
+};
+
+} // namespace experimental
+
+namespace internal {
+
+template <class Request, class Response>
+class UnimplementedReadReactor
+ : public experimental::ServerReadReactor<Request, Response> {
+ public:
+ void OnDone() override { delete this; }
+ void OnStarted(ServerContext*, Response*) override {
+ this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
+ }
+};
+
+template <class Request, class Response>
+class UnimplementedWriteReactor
+ : public experimental::ServerWriteReactor<Request, Response> {
+ public:
+ void OnDone() override { delete this; }
+ void OnStarted(ServerContext*, const Request*) override {
+ this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
+ }
+};
+
+template <class Request, class Response>
+class UnimplementedBidiReactor
+ : public experimental::ServerBidiReactor<Request, Response> {
+ public:
+ void OnDone() override { delete this; }
+ void OnStarted(ServerContext*) override {
+ this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
+ }
+};
+
+template <class RequestType, class ResponseType>
+class CallbackUnaryHandler : public MethodHandler {
+ public:
+ CallbackUnaryHandler(
+ std::function<void(ServerContext*, const RequestType*, ResponseType*,
+ experimental::ServerCallbackRpcController*)>
+ func)
+ : func_(func) {}
+ void RunHandler(const HandlerParameter& param) final {
+ // Arena allocate a controller structure (that includes request/response)
+ g_core_codegen_interface->grpc_call_ref(param.call->call());
+ auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ param.call->call(), sizeof(ServerCallbackRpcControllerImpl)))
+ ServerCallbackRpcControllerImpl(
+ param.server_context, param.call,
+ static_cast<RequestType*>(param.request),
+ std::move(param.call_requester));
+ Status status = param.status;
+
+ if (status.ok()) {
+ // Call the actual function handler and expect the user to call finish
+ CatchingCallback(func_, param.server_context, controller->request(),
+ controller->response(), controller);
+ } else {
+ // if deserialization failed, we need to fail the call
+ controller->Finish(status);
+ }
+ }
+
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ ByteBuffer buf;
+ buf.set_buffer(req);
+ auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call, sizeof(RequestType))) RequestType();
+ *status = SerializationTraits<RequestType>::Deserialize(&buf, request);
+ buf.Release();
+ if (status->ok()) {
+ return request;
+ }
+ request->~RequestType();
+ return nullptr;
+ }
+
+ private:
+ std::function<void(ServerContext*, const RequestType*, ResponseType*,
+ experimental::ServerCallbackRpcController*)>
+ func_;
+
+ // The implementation class of ServerCallbackRpcController is a private member
+ // of CallbackUnaryHandler since it is never exposed anywhere, and this allows
+ // it to take advantage of CallbackUnaryHandler's friendships.
+ class ServerCallbackRpcControllerImpl
+ : public experimental::ServerCallbackRpcController {
+ public:
+ void Finish(Status s) override {
+ finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },
+ &finish_ops_);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ finish_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // The response is dropped if the status is not OK.
+ if (s.ok()) {
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
+ finish_ops_.SendMessage(resp_));
+ } else {
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
+ }
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+ call_.PerformOps(&finish_ops_);
+ }
+
+ void SendInitialMetadata(std::function<void(bool)> f) override {
+ GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+ callbacks_outstanding_++;
+ // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14
+ // and if performance of this operation matters
+ meta_tag_.Set(call_.call(),
+ [this, f](bool ok) {
+ f(ok);
+ MaybeDone();
+ },
+ &meta_ops_);
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ meta_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ meta_ops_.set_core_cq_tag(&meta_tag_);
+ call_.PerformOps(&meta_ops_);
+ }
+
+ private:
+ friend class CallbackUnaryHandler<RequestType, ResponseType>;
+
+ ServerCallbackRpcControllerImpl(ServerContext* ctx, Call* call,
+ const RequestType* req,
+ std::function<void()> call_requester)
+ : ctx_(ctx),
+ call_(*call),
+ req_(req),
+ call_requester_(std::move(call_requester)) {
+ ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr);
+ }
+
+ ~ServerCallbackRpcControllerImpl() { req_->~RequestType(); }
+
+ const RequestType* request() { return req_; }
+ ResponseType* response() { return &resp_; }
+
+ void MaybeDone() {
+ if (--callbacks_outstanding_ == 0) {
+ grpc_call* call = call_.call();
+ auto call_requester = std::move(call_requester_);
+ this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor
+ g_core_codegen_interface->grpc_call_unref(call);
+ call_requester();
+ }
+ }
+
+ CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+ CallbackWithSuccessTag meta_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpServerSendStatus>
+ finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+
+ ServerContext* ctx_;
+ Call call_;
+ const RequestType* req_;
+ ResponseType resp_;
+ std::function<void()> call_requester_;
+ std::atomic_int callbacks_outstanding_{
+ 2}; // reserve for Finish and CompletionOp
+ };
+};
+
+template <class RequestType, class ResponseType>
+class CallbackClientStreamingHandler : public MethodHandler {
+ public:
+ CallbackClientStreamingHandler(
+ std::function<
+ experimental::ServerReadReactor<RequestType, ResponseType>*()>
+ func)
+ : func_(std::move(func)) {}
+ void RunHandler(const HandlerParameter& param) final {
+ // Arena allocate a reader structure (that includes response)
+ g_core_codegen_interface->grpc_call_ref(param.call->call());
+
+ experimental::ServerReadReactor<RequestType, ResponseType>* reactor =
+ param.status.ok()
+ ? CatchingReactorCreator<
+ experimental::ServerReadReactor<RequestType, ResponseType>>(
+ func_)
+ : nullptr;
+
+ if (reactor == nullptr) {
+ // if deserialization or reactor creator failed, we need to fail the call
+ reactor = new UnimplementedReadReactor<RequestType, ResponseType>;
+ }
+
+ auto* reader = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ param.call->call(), sizeof(ServerCallbackReaderImpl)))
+ ServerCallbackReaderImpl(param.server_context, param.call,
+ std::move(param.call_requester), reactor);
+
+ reader->BindReactor(reactor);
+ reactor->OnStarted(param.server_context, reader->response());
+ reader->MaybeDone();
+ }
+
+ private:
+ std::function<experimental::ServerReadReactor<RequestType, ResponseType>*()>
+ func_;
+
+ class ServerCallbackReaderImpl
+ : public experimental::ServerCallbackReader<RequestType> {
+ public:
+ void Finish(Status s) override {
+ finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },
+ &finish_ops_);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ finish_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // The response is dropped if the status is not OK.
+ if (s.ok()) {
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
+ finish_ops_.SendMessage(resp_));
+ } else {
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
+ }
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+ call_.PerformOps(&finish_ops_);
+ }
+
+ void SendInitialMetadata() override {
+ GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+ callbacks_outstanding_++;
+ meta_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnSendInitialMetadataDone(ok);
+ MaybeDone();
+ },
+ &meta_ops_);
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ meta_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ meta_ops_.set_core_cq_tag(&meta_tag_);
+ call_.PerformOps(&meta_ops_);
+ }
+
+ void Read(RequestType* req) override {
+ callbacks_outstanding_++;
+ read_ops_.RecvMessage(req);
+ call_.PerformOps(&read_ops_);
+ }
+
+ private:
+ friend class CallbackClientStreamingHandler<RequestType, ResponseType>;
+
+ ServerCallbackReaderImpl(
+ ServerContext* ctx, Call* call, std::function<void()> call_requester,
+ experimental::ServerReadReactor<RequestType, ResponseType>* reactor)
+ : ctx_(ctx),
+ call_(*call),
+ call_requester_(std::move(call_requester)),
+ reactor_(reactor) {
+ ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);
+ read_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadDone(ok);
+ MaybeDone();
+ },
+ &read_ops_);
+ read_ops_.set_core_cq_tag(&read_tag_);
+ }
+
+ ~ServerCallbackReaderImpl() {}
+
+ ResponseType* response() { return &resp_; }
+
+ void MaybeDone() {
+ if (--callbacks_outstanding_ == 0) {
+ reactor_->OnDone();
+ grpc_call* call = call_.call();
+ auto call_requester = std::move(call_requester_);
+ this->~ServerCallbackReaderImpl(); // explicitly call destructor
+ g_core_codegen_interface->grpc_call_unref(call);
+ call_requester();
+ }
+ }
+
+ CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+ CallbackWithSuccessTag meta_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpServerSendStatus>
+ finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
+ CallbackWithSuccessTag read_tag_;
+
+ ServerContext* ctx_;
+ Call call_;
+ ResponseType resp_;
+ std::function<void()> call_requester_;
+ experimental::ServerReadReactor<RequestType, ResponseType>* reactor_;
+ std::atomic_int callbacks_outstanding_{
+ 3}; // reserve for OnStarted, Finish, and CompletionOp
+ };
+};
+
+template <class RequestType, class ResponseType>
+class CallbackServerStreamingHandler : public MethodHandler {
+ public:
+ CallbackServerStreamingHandler(
+ std::function<
+ experimental::ServerWriteReactor<RequestType, ResponseType>*()>
+ func)
+ : func_(std::move(func)) {}
+ void RunHandler(const HandlerParameter& param) final {
+ // Arena allocate a writer structure
+ g_core_codegen_interface->grpc_call_ref(param.call->call());
+
+ experimental::ServerWriteReactor<RequestType, ResponseType>* reactor =
+ param.status.ok()
+ ? CatchingReactorCreator<
+ experimental::ServerWriteReactor<RequestType, ResponseType>>(
+ func_)
+ : nullptr;
+
+ if (reactor == nullptr) {
+ // if deserialization or reactor creator failed, we need to fail the call
+ reactor = new UnimplementedWriteReactor<RequestType, ResponseType>;
+ }
+
+ auto* writer = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ param.call->call(), sizeof(ServerCallbackWriterImpl)))
+ ServerCallbackWriterImpl(param.server_context, param.call,
+ static_cast<RequestType*>(param.request),
+ std::move(param.call_requester), reactor);
+ writer->BindReactor(reactor);
+ reactor->OnStarted(param.server_context, writer->request());
+ writer->MaybeDone();
+ }
+
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ ByteBuffer buf;
+ buf.set_buffer(req);
+ auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call, sizeof(RequestType))) RequestType();
+ *status = SerializationTraits<RequestType>::Deserialize(&buf, request);
+ buf.Release();
+ if (status->ok()) {
+ return request;
+ }
+ request->~RequestType();
+ return nullptr;
+ }
+
+ private:
+ std::function<experimental::ServerWriteReactor<RequestType, ResponseType>*()>
+ func_;
+
+ class ServerCallbackWriterImpl
+ : public experimental::ServerCallbackWriter<ResponseType> {
+ public:
+ void Finish(Status s) override {
+ finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },
+ &finish_ops_);
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+
+ if (!ctx_->sent_initial_metadata_) {
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ finish_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
+ call_.PerformOps(&finish_ops_);
+ }
+
+ void SendInitialMetadata() override {
+ GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+ callbacks_outstanding_++;
+ meta_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnSendInitialMetadataDone(ok);
+ MaybeDone();
+ },
+ &meta_ops_);
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ meta_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ meta_ops_.set_core_cq_tag(&meta_tag_);
+ call_.PerformOps(&meta_ops_);
+ }
+
+ void Write(const ResponseType* resp, WriteOptions options) override {
+ callbacks_outstanding_++;
+ if (options.is_last_message()) {
+ options.set_buffer_hint();
+ }
+ if (!ctx_->sent_initial_metadata_) {
+ write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ write_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(write_ops_.SendMessage(*resp, options).ok());
+ call_.PerformOps(&write_ops_);
+ }
+
+ void WriteAndFinish(const ResponseType* resp, WriteOptions options,
+ Status s) override {
+ // This combines the write into the finish callback
+ // Don't send any message if the status is bad
+ if (s.ok()) {
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(finish_ops_.SendMessage(*resp, options).ok());
+ }
+ Finish(std::move(s));
+ }
+
+ private:
+ friend class CallbackServerStreamingHandler<RequestType, ResponseType>;
+
+ ServerCallbackWriterImpl(
+ ServerContext* ctx, Call* call, const RequestType* req,
+ std::function<void()> call_requester,
+ experimental::ServerWriteReactor<RequestType, ResponseType>* reactor)
+ : ctx_(ctx),
+ call_(*call),
+ req_(req),
+ call_requester_(std::move(call_requester)),
+ reactor_(reactor) {
+ ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);
+ write_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWriteDone(ok);
+ MaybeDone();
+ },
+ &write_ops_);
+ write_ops_.set_core_cq_tag(&write_tag_);
+ }
+ ~ServerCallbackWriterImpl() { req_->~RequestType(); }
+
+ const RequestType* request() { return req_; }
+
+ void MaybeDone() {
+ if (--callbacks_outstanding_ == 0) {
+ reactor_->OnDone();
+ grpc_call* call = call_.call();
+ auto call_requester = std::move(call_requester_);
+ this->~ServerCallbackWriterImpl(); // explicitly call destructor
+ g_core_codegen_interface->grpc_call_unref(call);
+ call_requester();
+ }
+ }
+
+ CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+ CallbackWithSuccessTag meta_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpServerSendStatus>
+ finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+ CallbackWithSuccessTag write_tag_;
+
+ ServerContext* ctx_;
+ Call call_;
+ const RequestType* req_;
+ std::function<void()> call_requester_;
+ experimental::ServerWriteReactor<RequestType, ResponseType>* reactor_;
+ std::atomic_int callbacks_outstanding_{
+ 3}; // reserve for OnStarted, Finish, and CompletionOp
+ };
+};
+
+template <class RequestType, class ResponseType>
+class CallbackBidiHandler : public MethodHandler {
+ public:
+ CallbackBidiHandler(
+ std::function<
+ experimental::ServerBidiReactor<RequestType, ResponseType>*()>
+ func)
+ : func_(std::move(func)) {}
+ void RunHandler(const HandlerParameter& param) final {
+ g_core_codegen_interface->grpc_call_ref(param.call->call());
+
+ experimental::ServerBidiReactor<RequestType, ResponseType>* reactor =
+ param.status.ok()
+ ? CatchingReactorCreator<
+ experimental::ServerBidiReactor<RequestType, ResponseType>>(
+ func_)
+ : nullptr;
+
+ if (reactor == nullptr) {
+ // if deserialization or reactor creator failed, we need to fail the call
+ reactor = new UnimplementedBidiReactor<RequestType, ResponseType>;
+ }
+
+ auto* stream = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ param.call->call(), sizeof(ServerCallbackReaderWriterImpl)))
+ ServerCallbackReaderWriterImpl(param.server_context, param.call,
+ std::move(param.call_requester),
+ reactor);
+
+ stream->BindReactor(reactor);
+ reactor->OnStarted(param.server_context);
+ stream->MaybeDone();
+ }
+
+ private:
+ std::function<experimental::ServerBidiReactor<RequestType, ResponseType>*()>
+ func_;
+
+ class ServerCallbackReaderWriterImpl
+ : public experimental::ServerCallbackReaderWriter<RequestType,
+ ResponseType> {
+ public:
+ void Finish(Status s) override {
+ finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); },
+ &finish_ops_);
+ finish_ops_.set_core_cq_tag(&finish_tag_);
+
+ if (!ctx_->sent_initial_metadata_) {
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ finish_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
+ call_.PerformOps(&finish_ops_);
+ }
+
+ void SendInitialMetadata() override {
+ GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+ callbacks_outstanding_++;
+ meta_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnSendInitialMetadataDone(ok);
+ MaybeDone();
+ },
+ &meta_ops_);
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ meta_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ meta_ops_.set_core_cq_tag(&meta_tag_);
+ call_.PerformOps(&meta_ops_);
+ }
+
+ void Write(const ResponseType* resp, WriteOptions options) override {
+ callbacks_outstanding_++;
+ if (options.is_last_message()) {
+ options.set_buffer_hint();
+ }
+ if (!ctx_->sent_initial_metadata_) {
+ write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
+ ctx_->initial_metadata_flags());
+ if (ctx_->compression_level_set()) {
+ write_ops_.set_compression_level(ctx_->compression_level());
+ }
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(write_ops_.SendMessage(*resp, options).ok());
+ call_.PerformOps(&write_ops_);
+ }
+
+ void WriteAndFinish(const ResponseType* resp, WriteOptions options,
+ Status s) override {
+ // Don't send any message if the status is bad
+ if (s.ok()) {
+ // TODO(vjpai): don't assert
+ GPR_CODEGEN_ASSERT(finish_ops_.SendMessage(*resp, options).ok());
+ }
+ Finish(std::move(s));
+ }
+
+ void Read(RequestType* req) override {
+ callbacks_outstanding_++;
+ read_ops_.RecvMessage(req);
+ call_.PerformOps(&read_ops_);
+ }
+
+ private:
+ friend class CallbackBidiHandler<RequestType, ResponseType>;
+
+ ServerCallbackReaderWriterImpl(
+ ServerContext* ctx, Call* call, std::function<void()> call_requester,
+ experimental::ServerBidiReactor<RequestType, ResponseType>* reactor)
+ : ctx_(ctx),
+ call_(*call),
+ call_requester_(std::move(call_requester)),
+ reactor_(reactor) {
+ ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor);
+ write_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnWriteDone(ok);
+ MaybeDone();
+ },
+ &write_ops_);
+ write_ops_.set_core_cq_tag(&write_tag_);
+ read_tag_.Set(call_.call(),
+ [this](bool ok) {
+ reactor_->OnReadDone(ok);
+ MaybeDone();
+ },
+ &read_ops_);
+ read_ops_.set_core_cq_tag(&read_tag_);
+ }
+ ~ServerCallbackReaderWriterImpl() {}
+
+ void MaybeDone() {
+ if (--callbacks_outstanding_ == 0) {
+ reactor_->OnDone();
+ grpc_call* call = call_.call();
+ auto call_requester = std::move(call_requester_);
+ this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor
+ g_core_codegen_interface->grpc_call_unref(call);
+ call_requester();
+ }
+ }
+
+ CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+ CallbackWithSuccessTag meta_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpServerSendStatus>
+ finish_ops_;
+ CallbackWithSuccessTag finish_tag_;
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+ CallbackWithSuccessTag write_tag_;
+ CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
+ CallbackWithSuccessTag read_tag_;
+
+ ServerContext* ctx_;
+ Call call_;
+ std::function<void()> call_requester_;
+ experimental::ServerBidiReactor<RequestType, ResponseType>* reactor_;
+ std::atomic_int callbacks_outstanding_{
+ 3}; // reserve for OnStarted, Finish, and CompletionOp
+ };
+};
+
+} // namespace internal
+
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h
index b58f029de9..ccb5925e7d 100644
--- a/include/grpcpp/impl/codegen/server_context.h
+++ b/include/grpcpp/impl/codegen/server_context.h
@@ -26,11 +26,14 @@
#include <grpc/impl/codegen/compression_types.h>
#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_op_set.h>
+#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/time.h>
@@ -63,11 +66,20 @@ template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
+template <class RequestType, class ResponseType>
+class CallbackUnaryHandler;
+template <class RequestType, class ResponseType>
+class CallbackClientStreamingHandler;
+template <class RequestType, class ResponseType>
+class CallbackServerStreamingHandler;
+template <class RequestType, class ResponseType>
+class CallbackBidiHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class Call;
+class ServerReactor;
} // namespace internal
class CompletionQueue;
@@ -107,7 +119,7 @@ class ServerContext {
/// Return a \a gpr_timespec representation of the server call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
- /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+ /// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client side
/// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
///
@@ -115,13 +127,13 @@ class ServerContext {
/// to the client (which can happen explicitly, or implicitly when sending a
/// a response message or status to the client).
///
- /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+ /// \param key The metadata key. If \a value is binary data, it must
/// end in "-bin".
- /// \param meta_value The metadata value. If its value is binary, the key name
+ /// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
- /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+ /// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client
/// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
///
@@ -129,13 +141,13 @@ class ServerContext {
/// metadata to the client (which happens when the call is finished and a
/// status is sent to the client).
///
- /// \param meta_key The metadata key. If \a meta_value is binary data,
+ /// \param key The metadata key. If \a value is binary data,
/// it must end in "-bin".
- /// \param meta_value The metadata value. If its value is binary, the key name
+ /// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
- /// IsCancelled is always safe to call when using sync API.
+ /// IsCancelled is always safe to call when using sync or callback API.
/// When using async API, it is only safe to call IsCancelled after
/// the AsyncNotifyWhenDone tag has been delivered.
bool IsCancelled() const;
@@ -177,9 +189,9 @@ class ServerContext {
return compression_level_;
}
- /// Set \a algorithm to be the compression algorithm used for the server call.
+ /// Set \a level to be the compression level used for the server call.
///
- /// \param algorithm The compression algorithm used for the server call.
+ /// \param level The compression level used for the server call.
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
@@ -265,6 +277,14 @@ class ServerContext {
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
+ template <class RequestType, class ResponseType>
+ friend class ::grpc::internal::CallbackUnaryHandler;
+ template <class RequestType, class ResponseType>
+ friend class ::grpc::internal::CallbackClientStreamingHandler;
+ template <class RequestType, class ResponseType>
+ friend class ::grpc::internal::CallbackServerStreamingHandler;
+ template <class RequestType, class ResponseType>
+ friend class ::grpc::internal::CallbackBidiHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
friend class ::grpc::ClientContext;
@@ -275,7 +295,9 @@ class ServerContext {
class CompletionOp;
- void BeginCompletionOp(internal::Call* call);
+ void BeginCompletionOp(internal::Call* call,
+ std::function<void(bool)> callback,
+ internal::ServerReactor* reactor);
/// Return the tag queued by BeginCompletionOp()
internal::CompletionQueueTag* GetCompletionOpTag();
@@ -283,11 +305,30 @@ class ServerContext {
void set_call(grpc_call* call) { call_ = call; }
+ void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr);
+
+ void Clear();
+
+ void Setup(gpr_timespec deadline);
+
uint32_t initial_metadata_flags() const { return 0; }
+ experimental::ServerRpcInfo* set_server_rpc_info(
+ const char* method, internal::RpcMethod::RpcType type,
+ const std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
+ creators) {
+ if (creators.size() != 0) {
+ rpc_info_ = new experimental::ServerRpcInfo(this, method, type);
+ rpc_info_->RegisterInterceptors(creators);
+ }
+ return rpc_info_;
+ }
+
CompletionOp* completion_op_;
bool has_notify_when_done_tag_;
void* async_notify_when_done_tag_;
+ internal::CallbackWithSuccessTag completion_tag_;
gpr_timespec deadline_;
grpc_call* call_;
@@ -306,6 +347,8 @@ class ServerContext {
internal::CallOpSendMessage>
pending_ops_;
bool has_pending_ops_;
+
+ experimental::ServerRpcInfo* rpc_info_;
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/server_interceptor.h b/include/grpcpp/impl/codegen/server_interceptor.h
new file mode 100644
index 0000000000..cd7c0600b6
--- /dev/null
+++ b/include/grpcpp/impl/codegen/server_interceptor.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
+
+#include <atomic>
+#include <vector>
+
+#include <grpcpp/impl/codegen/interceptor.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+namespace grpc {
+
+class ServerContext;
+
+namespace internal {
+class InterceptorBatchMethodsImpl;
+}
+
+namespace experimental {
+class ServerRpcInfo;
+
+class ServerInterceptorFactoryInterface {
+ public:
+ virtual ~ServerInterceptorFactoryInterface() {}
+ virtual Interceptor* CreateServerInterceptor(ServerRpcInfo* info) = 0;
+};
+
+class ServerRpcInfo {
+ public:
+ enum class Type { UNARY, CLIENT_STREAMING, SERVER_STREAMING, BIDI_STREAMING };
+
+ ~ServerRpcInfo(){};
+
+ ServerRpcInfo(const ServerRpcInfo&) = delete;
+ ServerRpcInfo(ServerRpcInfo&&) = default;
+ ServerRpcInfo& operator=(ServerRpcInfo&&) = default;
+
+ // Getter methods
+ const char* method() const { return method_; }
+ Type type() const { return type_; }
+ grpc::ServerContext* server_context() { return ctx_; }
+
+ private:
+ static_assert(Type::UNARY ==
+ static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
+ "violated expectation about Type enum");
+ static_assert(Type::CLIENT_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
+ "violated expectation about Type enum");
+ static_assert(Type::SERVER_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
+ "violated expectation about Type enum");
+ static_assert(Type::BIDI_STREAMING ==
+ static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
+ "violated expectation about Type enum");
+
+ ServerRpcInfo(grpc::ServerContext* ctx, const char* method,
+ internal::RpcMethod::RpcType type)
+ : ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {
+ ref_.store(1);
+ }
+
+ // Runs interceptor at pos \a pos.
+ void RunInterceptor(
+ experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
+ GPR_CODEGEN_ASSERT(pos < interceptors_.size());
+ interceptors_[pos]->Intercept(interceptor_methods);
+ }
+
+ void RegisterInterceptors(
+ const std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
+ creators) {
+ for (const auto& creator : creators) {
+ interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
+ creator->CreateServerInterceptor(this)));
+ }
+ }
+
+ void Ref() { ref_++; }
+ void Unref() {
+ if (--ref_ == 0) {
+ delete this;
+ }
+ }
+
+ grpc::ServerContext* ctx_ = nullptr;
+ const char* method_ = nullptr;
+ const Type type_;
+ std::atomic_int ref_;
+ std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
+
+ friend class internal::InterceptorBatchMethodsImpl;
+ friend class grpc::ServerContext;
+};
+
+} // namespace experimental
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h
index 237991cde6..e0e2629827 100644
--- a/include/grpcpp/impl/codegen/server_interface.h
+++ b/include/grpcpp/impl/codegen/server_interface.h
@@ -21,10 +21,12 @@
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_hook.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
+#include <grpcpp/impl/codegen/server_context.h>
namespace grpc {
@@ -148,44 +150,69 @@ class ServerInterface : public internal::CallHook {
public:
BaseAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
- CompletionQueue* call_cq, void* tag,
+ CompletionQueue* call_cq,
+ ServerCompletionQueue* notification_cq, void* tag,
bool delete_on_finalize);
virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override;
+ private:
+ void ContinueFinalizeResultAfterInterception();
+
protected:
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
+ ServerCompletionQueue* const notification_cq_;
void* const tag_;
const bool delete_on_finalize_;
grpc_call* call_;
+ internal::Call call_wrapper_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
+ bool done_intercepting_;
};
+ /// RegisteredAsyncRequest is not part of the C++ API
class RegisteredAsyncRequest : public BaseAsyncRequest {
public:
RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
- CompletionQueue* call_cq, void* tag);
-
- // uses BaseAsyncRequest::FinalizeResult
+ CompletionQueue* call_cq,
+ ServerCompletionQueue* notification_cq, void* tag,
+ const char* name, internal::RpcMethod::RpcType type);
+
+ virtual bool FinalizeResult(void** tag, bool* status) override {
+ /* If we are done intercepting, then there is nothing more for us to do */
+ if (done_intercepting_) {
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(),
+ context_->set_server_rpc_info(name_, type_,
+ *server_->interceptor_creators()));
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
protected:
void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
ServerCompletionQueue* notification_cq);
+ const char* name_;
+ const internal::RpcMethod::RpcType type_;
};
class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
- NoPayloadAsyncRequest(void* registered_method, ServerInterface* server,
- ServerContext* context,
+ NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
+ ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag)
- : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
- IssueRequest(registered_method, nullptr, notification_cq);
+ : RegisteredAsyncRequest(
+ server, context, stream, call_cq, notification_cq, tag,
+ registered_method->name(), registered_method->method_type()) {
+ IssueRequest(registered_method->server_tag(), nullptr, notification_cq);
}
// uses RegisteredAsyncRequest::FinalizeResult
@@ -194,13 +221,15 @@ class ServerInterface : public internal::CallHook {
template <class Message>
class PayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
- PayloadAsyncRequest(void* registered_method, ServerInterface* server,
- ServerContext* context,
+ PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
+ ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
Message* request)
- : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
+ : RegisteredAsyncRequest(
+ server, context, stream, call_cq, notification_cq, tag,
+ registered_method->name(), registered_method->method_type()),
registered_method_(registered_method),
server_(server),
context_(context),
@@ -209,7 +238,8 @@ class ServerInterface : public internal::CallHook {
notification_cq_(notification_cq),
tag_(tag),
request_(request) {
- IssueRequest(registered_method, payload_.bbuf_ptr(), notification_cq);
+ IssueRequest(registered_method->server_tag(), payload_.bbuf_ptr(),
+ notification_cq);
}
~PayloadAsyncRequest() {
@@ -217,6 +247,10 @@ class ServerInterface : public internal::CallHook {
}
bool FinalizeResult(void** tag, bool* status) override {
+ /* If we are done intercepting, then there is nothing more for us to do */
+ if (done_intercepting_) {
+ return RegisteredAsyncRequest::FinalizeResult(tag, status);
+ }
if (*status) {
if (!payload_.Valid() || !SerializationTraits<Message>::Deserialize(
payload_.bbuf_ptr(), request_)
@@ -235,15 +269,20 @@ class ServerInterface : public internal::CallHook {
return false;
}
}
+ /* Set interception point for recv message */
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ interceptor_methods_.SetRecvMessage(request_);
return RegisteredAsyncRequest::FinalizeResult(tag, status);
}
private:
- void* const registered_method_;
+ internal::RpcServiceMethod* const registered_method_;
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
+
ServerCompletionQueue* const notification_cq_;
void* const tag_;
Message* const request_;
@@ -272,9 +311,8 @@ class ServerInterface : public internal::CallHook {
ServerCompletionQueue* notification_cq, void* tag,
Message* message) {
GPR_CODEGEN_ASSERT(method);
- new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
- stream, call_cq, notification_cq, tag,
- message);
+ new PayloadAsyncRequest<Message>(method, this, context, stream, call_cq,
+ notification_cq, tag, message);
}
void RequestAsyncCall(internal::RpcServiceMethod* method,
@@ -283,8 +321,8 @@ class ServerInterface : public internal::CallHook {
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
GPR_CODEGEN_ASSERT(method);
- new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
- call_cq, notification_cq, tag);
+ new NoPayloadAsyncRequest(method, this, context, stream, call_cq,
+ notification_cq, tag);
}
void RequestAsyncGenericCall(GenericServerContext* context,
@@ -295,6 +333,28 @@ class ServerInterface : public internal::CallHook {
new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
tag, true);
}
+
+ private:
+ // EXPERIMENTAL
+ // Getter method for the vector of interceptor factory objects.
+ // Returns a nullptr (rather than being pure) since this is a post-1.0 method
+ // and adding a new pure method to an interface would be a breaking change
+ // (even though this is private and non-API)
+ virtual std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>*
+ interceptor_creators() {
+ return nullptr;
+ }
+
+ // EXPERIMENTAL
+ // A method to get the callbackable completion queue associated with this
+ // server. If the return value is nullptr, this server doesn't support
+ // callback operations.
+ // TODO(vjpai): Consider a better default like using a global CQ
+ // Returns nullptr (rather than being pure) since this is a post-1.0 method
+ // and adding a new pure method to an interface would be a breaking change
+ // (even though this is private and non-API)
+ virtual CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h
index 9f1a052168..332a04c294 100644
--- a/include/grpcpp/impl/codegen/service_type.h
+++ b/include/grpcpp/impl/codegen/service_type.h
@@ -71,7 +71,20 @@ class Service {
bool has_synchronous_methods() const {
for (auto it = methods_.begin(); it != methods_.end(); ++it) {
- if (*it && (*it)->handler() != nullptr) {
+ if (*it &&
+ (*it)->api_type() == internal::RpcServiceMethod::ApiType::SYNC) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool has_callback_methods() const {
+ for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+ if (*it && ((*it)->api_type() ==
+ internal::RpcServiceMethod::ApiType::CALL_BACK ||
+ (*it)->api_type() ==
+ internal::RpcServiceMethod::ApiType::RAW_CALL_BACK)) {
return true;
}
}
@@ -88,6 +101,43 @@ class Service {
}
protected:
+ // TODO(vjpai): Promote experimental contents once callback API is accepted
+ class experimental_type {
+ public:
+ explicit experimental_type(Service* service) : service_(service) {}
+
+ void MarkMethodCallback(int index, internal::MethodHandler* handler) {
+ // This does not have to be a hard error, however no one has approached us
+ // with a use case yet. Please file an issue if you believe you have one.
+ size_t idx = static_cast<size_t>(index);
+ GPR_CODEGEN_ASSERT(
+ service_->methods_[idx].get() != nullptr &&
+ "Cannot mark the method as 'callback' because it has already been "
+ "marked as 'generic'.");
+ service_->methods_[idx]->SetHandler(handler);
+ service_->methods_[idx]->SetServerApiType(
+ internal::RpcServiceMethod::ApiType::CALL_BACK);
+ }
+
+ void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
+ // This does not have to be a hard error, however no one has approached us
+ // with a use case yet. Please file an issue if you believe you have one.
+ size_t idx = static_cast<size_t>(index);
+ GPR_CODEGEN_ASSERT(
+ service_->methods_[idx].get() != nullptr &&
+ "Cannot mark the method as 'raw callback' because it has already "
+ "been marked as 'generic'.");
+ service_->methods_[idx]->SetHandler(handler);
+ service_->methods_[idx]->SetServerApiType(
+ internal::RpcServiceMethod::ApiType::RAW_CALL_BACK);
+ }
+
+ private:
+ Service* service_;
+ };
+
+ experimental_type experimental() { return experimental_type(this); }
+
template <class Message>
void RequestAsyncUnary(int index, ServerContext* context, Message* request,
internal::ServerAsyncStreamingInterface* stream,
@@ -138,8 +188,7 @@ class Service {
methods_[idx].get() != nullptr &&
"Cannot mark the method as 'async' because it has already been "
"marked as 'generic'.");
- methods_[idx]->SetServerAsyncType(
- internal::RpcServiceMethod::AsyncType::ASYNC);
+ methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::ASYNC);
}
void MarkMethodRaw(int index) {
@@ -149,8 +198,7 @@ class Service {
GPR_CODEGEN_ASSERT(methods_[idx].get() != nullptr &&
"Cannot mark the method as 'raw' because it has already "
"been marked as 'generic'.");
- methods_[idx]->SetServerAsyncType(
- internal::RpcServiceMethod::AsyncType::RAW);
+ methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::RAW);
}
void MarkMethodGeneric(int index) {
diff --git a/include/grpcpp/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h
index cbfcf25d0a..6981076f04 100644
--- a/include/grpcpp/impl/codegen/sync_stream.h
+++ b/include/grpcpp/impl/codegen/sync_stream.h
@@ -250,7 +250,7 @@ class ClientReader final : public ClientReaderInterface<R> {
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok());
@@ -327,7 +327,7 @@ class ClientWriter : public ClientWriterInterface<W> {
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
- ops.SendInitialMetadata(context_->send_initial_metadata_,
+ ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
@@ -386,7 +386,7 @@ class ClientWriter : public ClientWriterInterface<W> {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
@@ -498,7 +498,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
- ops.SendInitialMetadata(context_->send_initial_metadata_,
+ ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
@@ -557,7 +557,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
@@ -583,7 +583,7 @@ class ServerReader final : public ServerReaderInterface<R> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -635,7 +635,7 @@ class ServerWriter final : public ServerWriterInterface<W> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -660,7 +660,7 @@ class ServerWriter final : public ServerWriterInterface<W> {
return false;
}
if (!ctx_->sent_initial_metadata_) {
- ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
@@ -708,7 +708,7 @@ class ServerReaderWriterBody final {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
CallOpSet<CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -738,7 +738,7 @@ class ServerReaderWriterBody final {
return false;
}
if (!ctx_->sent_initial_metadata_) {
- ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
diff --git a/include/grpcpp/security/credentials.h b/include/grpcpp/security/credentials.h
index 8dfbdec3e6..d8c9e04d77 100644
--- a/include/grpcpp/security/credentials.h
+++ b/include/grpcpp/security/credentials.h
@@ -46,8 +46,8 @@ std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace experimental
@@ -80,8 +80,8 @@ class ChannelCredentials : private GrpcLibraryCodegen {
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
virtual std::shared_ptr<Channel> CreateChannel(
@@ -91,8 +91,8 @@ class ChannelCredentials : private GrpcLibraryCodegen {
// implemented as a virtual function so that it does not break API.
virtual std::shared_ptr<Channel> CreateChannelWithInterceptors(
const grpc::string& target, const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
return nullptr;
};
diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h
index 8d3e856502..cdcac186cb 100644
--- a/include/grpcpp/server.h
+++ b/include/grpcpp/server.h
@@ -111,8 +111,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// interceptors
std::shared_ptr<Channel> InProcessChannelWithInterceptors(
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
private:
@@ -174,7 +174,11 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
- grpc_resource_quota* server_rq = nullptr);
+ grpc_resource_quota* server_rq = nullptr,
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators = std::vector<std::unique_ptr<
+ experimental::ServerInterceptorFactoryInterface>>());
/// Start the server.
///
@@ -187,11 +191,17 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
grpc_server* server() override { return server_; };
private:
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>*
+ interceptor_creators() override {
+ return &interceptor_creators_;
+ }
+
friend class AsyncGenericService;
friend class ServerBuilder;
friend class ServerInitializer;
class SyncRequest;
+ class CallbackRequest;
class UnimplementedAsyncRequest;
class UnimplementedAsyncResponse;
@@ -214,8 +224,18 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
return max_receive_message_size_;
};
+ CompletionQueue* CallbackCQ() override;
+
ServerInitializer* initializer();
+ // A vector of interceptor factory objects.
+ // This should be destroyed after health_check_service_ and this requirement
+ // is satisfied by declaring interceptor_creators_ before
+ // health_check_service_. (C++ mandates that member objects be destroyed in
+ // the reverse order of initialization.)
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators_;
+
const int max_receive_message_size_;
/// The following completion queues are ONLY used in case of Sync API
@@ -228,6 +248,9 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// the \a sync_server_cqs)
std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_;
+ /// Outstanding callback requests
+ std::vector<std::unique_ptr<CallbackRequest>> callback_reqs_;
+
// Server status
std::mutex mu_;
bool started_;
@@ -251,6 +274,13 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
// A special handler for resource exhausted in sync case
std::unique_ptr<internal::MethodHandler> resource_exhausted_handler_;
+
+ // callback_cq_ references the callbackable completion queue associated
+ // with this server (if any). It is set on the first call to CallbackCQ().
+ // It is _not owned_ by the server; ownership belongs with its internal
+ // shutdown callback tag (invoked when the CQ is fully shutdown).
+ // It is protected by mu_
+ CompletionQueue* callback_cq_ = nullptr;
};
} // namespace grpc
diff --git a/include/grpcpp/server_builder.h b/include/grpcpp/server_builder.h
index a58a59c2d8..028b8cffaa 100644
--- a/include/grpcpp/server_builder.h
+++ b/include/grpcpp/server_builder.h
@@ -28,6 +28,7 @@
#include <grpc/support/cpu.h>
#include <grpc/support/workaround_list.h>
#include <grpcpp/impl/channel_argument_option.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/impl/server_builder_plugin.h>
#include <grpcpp/support/config.h>
@@ -212,6 +213,29 @@ class ServerBuilder {
/// doc/workarounds.md.
ServerBuilder& EnableWorkaround(grpc_workaround_list id);
+ /// NOTE: class experimental_type is not part of the public API of this class.
+ /// TODO(yashykt): Integrate into public API when this is no longer
+ /// experimental.
+ class experimental_type {
+ public:
+ explicit experimental_type(ServerBuilder* builder) : builder_(builder) {}
+
+ void SetInterceptorCreators(
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators) {
+ builder_->interceptor_creators_ = std::move(interceptor_creators);
+ }
+
+ private:
+ ServerBuilder* builder_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
protected:
/// Experimental, to be deprecated
struct Port {
@@ -297,6 +321,8 @@ class ServerBuilder {
grpc_compression_algorithm algorithm;
} maybe_default_compression_algorithm_;
uint32_t enabled_compression_algorithms_bitset_;
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators_;
};
} // namespace grpc
diff --git a/include/grpcpp/support/server_callback.h b/include/grpcpp/support/server_callback.h
new file mode 100644
index 0000000000..b0aeeb53c5
--- /dev/null
+++ b/include/grpcpp/support/server_callback.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_SUPPORT_SERVER_CALLBACK_H
+#define GRPCPP_SUPPORT_SERVER_CALLBACK_H
+
+#include <grpcpp/impl/codegen/server_callback.h>
+
+#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_H
diff --git a/package.xml b/package.xml
index c90cee8fe9..bdcb12bfc5 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
<date>2018-01-19</date>
<time>16:06:07</time>
<version>
- <release>1.17.0dev</release>
- <api>1.17.0dev</api>
+ <release>1.18.0dev</release>
+ <api>1.18.0dev</api>
</version>
<stability>
<release>beta</release>
@@ -191,6 +191,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/context_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/flow_control.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.h" role="src" />
@@ -249,7 +250,7 @@
<file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.h" role="src" />
- <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.h" role="src" />
+ <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_shared_resource.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h" role="src" />
@@ -286,20 +287,18 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.h" role="src" />
- <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/local_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session.h" role="src" />
@@ -345,6 +344,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/call_combiner.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/combiner.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/iomgr/dynamic_annotations.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/error.h" role="src" />
@@ -444,6 +444,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/uri/uri_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
@@ -615,12 +616,14 @@
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/uri/uri_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/debug/trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_plugin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/context_list.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/flow_control.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.cc" role="src" />
@@ -687,7 +690,7 @@
<file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.cc" role="src" />
- <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_shared_resource.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc" role="src" />
@@ -729,19 +732,17 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.cc" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.cc" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.c" role="src" />
- <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/local_transport_security.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc" role="src" />
diff --git a/requirements.bazel.txt b/requirements.bazel.txt
index 16f31f9e94..61e529a6ec 100644
--- a/requirements.bazel.txt
+++ b/requirements.bazel.txt
@@ -8,3 +8,8 @@ wheel>=0.29
futures>=2.2.0
google-auth>=1.0.0
oauth2client==4.1.0
+requests>=2.14.2
+urllib3==1.22
+chardet==3.0.4
+certifi==2017.4.17
+idna==2.7
diff --git a/setup.cfg b/setup.cfg
index 218792e674..125ec93491 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -15,3 +15,6 @@ exclude=.*protoc_plugin/protoc_plugin_test\.proto$
# Style settings
[yapf]
based_on_style = google
+
+[metadata]
+license_files = LICENSE
diff --git a/setup.py b/setup.py
index 388e629ec2..7bdfc99e24 100644
--- a/setup.py
+++ b/setup.py
@@ -57,11 +57,13 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.abspath(PYTHON_STEM))
# Break import-style to ensure we can actually find our in-repo dependencies.
+import _parallel_compile_patch
import _spawn_patch
import commands
import grpc_core_dependencies
import grpc_version
+_parallel_compile_patch.monkeypatch_compile_maybe()
_spawn_patch.monkeypatch_spawn()
LICENSE = 'Apache License 2.0'
@@ -85,24 +87,44 @@ CLASSIFIERS = [
# present, then it will still attempt to use Cython.
BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+
# Export this variable to use the system installation of openssl. You need to
# have the header files installed (in /usr/include/openssl) and during
-# runtime, the shared libary must be installed
+# runtime, the shared library must be installed
BUILD_WITH_SYSTEM_OPENSSL = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_OPENSSL',
False)
# Export this variable to use the system installation of zlib. You need to
# have the header files installed (in /usr/include/) and during
-# runtime, the shared libary must be installed
+# runtime, the shared library must be installed
BUILD_WITH_SYSTEM_ZLIB = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_ZLIB',
False)
# Export this variable to use the system installation of cares. You need to
# have the header files installed (in /usr/include/) and during
-# runtime, the shared libary must be installed
+# runtime, the shared library must be installed
BUILD_WITH_SYSTEM_CARES = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_CARES',
False)
+# For local development use only: This skips building gRPC Core and its
+# dependencies, including protobuf and boringssl. This allows "incremental"
+# compilation by first building gRPC Core using make, then building only the
+# Python/Cython layers here.
+#
+# Note that this requires libboringssl.a in the libs/{dbg,opt}/ directory, which
+# may require configuring make to not use the system openssl implementation:
+#
+# make HAS_SYSTEM_OPENSSL_ALPN=0
+#
+# TODO(ericgribkoff) Respect the BUILD_WITH_SYSTEM_* flags alongside this option
+USE_PREBUILT_GRPC_CORE = os.environ.get(
+ 'GRPC_PYTHON_USE_PREBUILT_GRPC_CORE', False)
+
+
+# If this environmental variable is set, GRPC will not try to be compatible with
+# libc versions old than the one it was compiled against.
+DISABLE_LIBC_COMPATIBILITY = os.environ.get('GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY', False)
+
# Environment variable to determine whether or not to enable coverage analysis
# in Cython modules.
ENABLE_CYTHON_TRACING = os.environ.get(
@@ -198,11 +220,11 @@ if BUILD_WITH_SYSTEM_ZLIB:
if BUILD_WITH_SYSTEM_CARES:
EXTENSION_LIBRARIES += ('cares',)
-DEFINE_MACROS = (
- ('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
- ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1))
+DEFINE_MACROS = (('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600))
+if not DISABLE_LIBC_COMPATIBILITY:
+ DEFINE_MACROS += (('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
if "win32" in sys.platform:
- # TODO(zyc): Re-enble c-ares on x64 and x86 windows after fixing the
+ # TODO(zyc): Re-enable c-ares on x64 and x86 windows after fixing the
# ares_library_init compilation issue
DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1),
('GRPC_ARES', 0), ('NTDDI_VERSION', 0x06000000),
@@ -243,7 +265,7 @@ def cython_extensions_and_necessity():
for name in CYTHON_EXTENSION_MODULE_NAMES]
config = os.environ.get('CONFIG', 'opt')
prefix = 'libs/' + config + '/'
- if "darwin" in sys.platform:
+ if "darwin" in sys.platform or USE_PREBUILT_GRPC_CORE:
extra_objects = [prefix + 'libares.a',
prefix + 'libboringssl.a',
prefix + 'libgpr.a',
@@ -283,8 +305,7 @@ if not PY3:
INSTALL_REQUIRES += ('futures>=2.2.0', 'enum34>=1.0.4')
SETUP_REQUIRES = INSTALL_REQUIRES + (
- 'sphinx>=1.3',
- 'sphinx_rtd_theme>=0.1.8',
+ 'Sphinx~=1.8.1',
'six>=1.10',
) if ENABLE_DOCUMENTATION_BUILD else ()
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 56716493dc..b004687250 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -132,9 +132,11 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"grpcpp/impl/codegen/async_generic_service.h",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
+ "grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/method_handler_impl.h",
"grpcpp/impl/codegen/proto_utils.h",
"grpcpp/impl/codegen/rpc_method.h",
+ "grpcpp/impl/codegen/server_callback.h",
"grpcpp/impl/codegen/service_type.h",
"grpcpp/impl/codegen/status.h",
"grpcpp/impl/codegen/stub_options.h",
@@ -579,11 +581,22 @@ void PrintHeaderClientMethodCallbackInterfaces(
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)>) = 0;\n");
} else if (ClientOnlyStreaming(method)) {
- // TODO(vjpai): Add support for client-side streaming
+ printer->Print(*vars,
+ "virtual void $Method$(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::experimental::ClientWriteReactor< $Request$>* "
+ "reactor) = 0;\n");
} else if (ServerOnlyStreaming(method)) {
- // TODO(vjpai): Add support for server-side streaming
+ printer->Print(*vars,
+ "virtual void $Method$(::grpc::ClientContext* context, "
+ "$Request$* request, "
+ "::grpc::experimental::ClientReadReactor< $Response$>* "
+ "reactor) = 0;\n");
} else if (method->BidiStreaming()) {
- // TODO(vjpai): Add support for bidi streaming
+ printer->Print(*vars,
+ "virtual void $Method$(::grpc::ClientContext* context, "
+ "::grpc::experimental::ClientBidiReactor< "
+ "$Request$,$Response$>* reactor) = 0;\n");
}
}
@@ -630,11 +643,23 @@ void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer,
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)>) override;\n");
} else if (ClientOnlyStreaming(method)) {
- // TODO(vjpai): Add support for client-side streaming
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::experimental::ClientWriteReactor< $Request$>* "
+ "reactor) override;\n");
} else if (ServerOnlyStreaming(method)) {
- // TODO(vjpai): Add support for server-side streaming
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "$Request$* request, "
+ "::grpc::experimental::ClientReadReactor< $Response$>* "
+ "reactor) override;\n");
+
} else if (method->BidiStreaming()) {
- // TODO(vjpai): Add support for bidi streaming
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "::grpc::experimental::ClientBidiReactor< "
+ "$Request$,$Response$>* reactor) override;\n");
}
}
@@ -700,9 +725,9 @@ void PrintHeaderServerMethodSync(grpc_generator::Printer* printer,
printer->Print(method->GetTrailingComments("//").c_str());
}
-// Helper generator. Disabled the sync API for Request and Response, then adds
+// Helper generator. Disables the sync API for Request and Response, then adds
// in an async API for RealRequest and RealResponse types. This is to be used
-// to generate async and raw APIs.
+// to generate async and raw async APIs.
void PrintHeaderServerAsyncMethodsHelper(
grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) {
@@ -829,6 +854,213 @@ void PrintHeaderServerMethodAsync(grpc_generator::Printer* printer,
printer->Print(*vars, "};\n");
}
+// Helper generator. Disables the sync API for Request and Response, then adds
+// in a callback API for RealRequest and RealResponse types. This is to be used
+// to generate callback and raw callback APIs.
+void PrintHeaderServerCallbackMethodsHelper(
+ grpc_generator::Printer* printer, const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars) {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "virtual void $Method$("
+ "::grpc::ServerContext* context, const $RealRequest$* request, "
+ "$RealResponse$* response, "
+ "::grpc::experimental::ServerCallbackRpcController* "
+ "controller) { controller->Finish(::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\")); }\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(*vars,
+ "virtual ::grpc::experimental::ServerReadReactor< "
+ "$RealRequest$, $RealResponse$>* $Method$() {\n"
+ " return new ::grpc::internal::UnimplementedReadReactor<\n"
+ " $RealRequest$, $RealResponse$>;}\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) override "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(*vars,
+ "virtual ::grpc::experimental::ServerWriteReactor< "
+ "$RealRequest$, $RealResponse$>* $Method$() {\n"
+ " return new ::grpc::internal::UnimplementedWriteReactor<\n"
+ " $RealRequest$, $RealResponse$>;}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+ " override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(*vars,
+ "virtual ::grpc::experimental::ServerBidiReactor< "
+ "$RealRequest$, $RealResponse$>* $Method$() {\n"
+ " return new ::grpc::internal::UnimplementedBidiReactor<\n"
+ " $RealRequest$, $RealResponse$>;}\n");
+ }
+}
+
+void PrintHeaderServerMethodCallback(
+ grpc_generator::Printer* printer, const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars) {
+ (*vars)["Method"] = method->name();
+ // These will be disabled
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ // These will be used for the callback API
+ (*vars)["RealRequest"] = method->input_type_name();
+ (*vars)["RealResponse"] = method->output_type_name();
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(
+ *vars,
+ "class ExperimentalWithCallbackMethod_$Method$ : public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars, "ExperimentalWithCallbackMethod_$Method$() {\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackUnaryHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this](::grpc::ServerContext* context,\n"
+ " const $RealRequest$* request,\n"
+ " $RealResponse$* response,\n"
+ " ::grpc::experimental::ServerCallbackRpcController* "
+ "controller) {\n"
+ " return this->$"
+ "Method$(context, request, response, controller);\n"
+ " }));\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackClientStreamingHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackServerStreamingHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackBidiHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ }
+ printer->Print(*vars, "}\n");
+ printer->Print(*vars,
+ "~ExperimentalWithCallbackMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ PrintHeaderServerCallbackMethodsHelper(printer, method, vars);
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderServerMethodRawCallback(
+ grpc_generator::Printer* printer, const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars) {
+ (*vars)["Method"] = method->name();
+ // These will be disabled
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ // These will be used for raw API
+ (*vars)["RealRequest"] = "::grpc::ByteBuffer";
+ (*vars)["RealResponse"] = "::grpc::ByteBuffer";
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class ExperimentalWithRawCallbackMethod_$Method$ : public "
+ "BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars, "ExperimentalWithRawCallbackMethod_$Method$() {\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackUnaryHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this](::grpc::ServerContext* context,\n"
+ " const $RealRequest$* request,\n"
+ " $RealResponse$* response,\n"
+ " ::grpc::experimental::ServerCallbackRpcController* "
+ "controller) {\n"
+ " this->$"
+ "Method$(context, request, response, controller);\n"
+ " }));\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackClientStreamingHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackServerStreamingHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
+ " new ::grpc::internal::CallbackBidiHandler< "
+ "$RealRequest$, $RealResponse$>(\n"
+ " [this] { return this->$Method$(); }));\n");
+ }
+ printer->Print(*vars, "}\n");
+ printer->Print(*vars,
+ "~ExperimentalWithRawCallbackMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ PrintHeaderServerCallbackMethodsHelper(printer, method, vars);
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
void PrintHeaderServerMethodStreamedUnary(
grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) {
@@ -1137,7 +1369,7 @@ void PrintHeaderService(grpc_generator::Printer* printer,
printer->Print("typedef ");
for (int i = 0; i < service->method_count(); ++i) {
- (*vars)["method_name"] = service->method(i).get()->name();
+ (*vars)["method_name"] = service->method(i)->name();
printer->Print(*vars, "WithAsyncMethod_$method_name$<");
}
printer->Print("Service");
@@ -1146,6 +1378,24 @@ void PrintHeaderService(grpc_generator::Printer* printer,
}
printer->Print(" AsyncService;\n");
+ // Server side - Callback
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodCallback(printer, service->method(i).get(), vars);
+ }
+
+ printer->Print("typedef ");
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i)->name();
+ printer->Print(*vars, "ExperimentalWithCallbackMethod_$method_name$<");
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(" >");
+ }
+ printer->Print(" ExperimentalCallbackService;\n");
+
// Server side - Generic
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Idx"] = as_string(i);
@@ -1158,6 +1408,12 @@ void PrintHeaderService(grpc_generator::Printer* printer,
PrintHeaderServerMethodRaw(printer, service->method(i).get(), vars);
}
+ // Server side - Raw Callback
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodRawCallback(printer, service->method(i).get(), vars);
+ }
+
// Server side - Streamed Unary
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Idx"] = as_string(i);
@@ -1167,7 +1423,7 @@ void PrintHeaderService(grpc_generator::Printer* printer,
printer->Print("typedef ");
for (int i = 0; i < service->method_count(); ++i) {
- (*vars)["method_name"] = service->method(i).get()->name();
+ (*vars)["method_name"] = service->method(i)->name();
if (service->method(i)->NoStreaming()) {
printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<");
}
@@ -1189,7 +1445,7 @@ void PrintHeaderService(grpc_generator::Printer* printer,
printer->Print("typedef ");
for (int i = 0; i < service->method_count(); ++i) {
- (*vars)["method_name"] = service->method(i).get()->name();
+ (*vars)["method_name"] = service->method(i)->name();
auto method = service->method(i);
if (ServerOnlyStreaming(method.get())) {
printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
@@ -1207,7 +1463,7 @@ void PrintHeaderService(grpc_generator::Printer* printer,
// Server side - typedef for controlled both unary and server-side streaming
printer->Print("typedef ");
for (int i = 0; i < service->method_count(); ++i) {
- (*vars)["method_name"] = service->method(i).get()->name();
+ (*vars)["method_name"] = service->method(i)->name();
auto method = service->method(i);
if (ServerOnlyStreaming(method.get())) {
printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
@@ -1333,6 +1589,7 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
"grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/method_handler_impl.h",
"grpcpp/impl/codegen/rpc_service_method.h",
+ "grpcpp/impl/codegen/server_callback.h",
"grpcpp/impl/codegen/service_type.h",
"grpcpp/impl/codegen/sync_stream.h"};
std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
@@ -1417,7 +1674,19 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"context, response);\n"
"}\n\n");
- // TODO(vjpai): Add callback version
+ printer->Print(
+ *vars,
+ "void $ns$$Service$::"
+ "Stub::experimental_async::$Method$(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::experimental::ClientWriteReactor< $Request$>* reactor) {\n");
+ printer->Print(*vars,
+ " ::grpc::internal::ClientCallbackWriterFactory< "
+ "$Request$>::Create("
+ "stub_->channel_.get(), "
+ "stub_->rpcmethod_$Method$_, "
+ "context, response, reactor);\n"
+ "}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
@@ -1451,7 +1720,19 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"context, request);\n"
"}\n\n");
- // TODO(vjpai): Add callback version
+ printer->Print(
+ *vars,
+ "void $ns$$Service$::Stub::experimental_async::$Method$(::grpc::"
+ "ClientContext* context, "
+ "$Request$* request, "
+ "::grpc::experimental::ClientReadReactor< $Response$>* reactor) {\n");
+ printer->Print(*vars,
+ " ::grpc::internal::ClientCallbackReaderFactory< "
+ "$Response$>::Create("
+ "stub_->channel_.get(), "
+ "stub_->rpcmethod_$Method$_, "
+ "context, request, reactor);\n"
+ "}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
@@ -1485,7 +1766,19 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"context);\n"
"}\n\n");
- // TODO(vjpai): Add callback version
+ printer->Print(
+ *vars,
+ "void $ns$$Service$::Stub::experimental_async::$Method$(::grpc::"
+ "ClientContext* context, "
+ "::grpc::experimental::ClientBidiReactor< $Request$,$Response$>* "
+ "reactor) {\n");
+ printer->Print(*vars,
+ " ::grpc::internal::ClientCallbackReaderWriterFactory< "
+ "$Request$,$Response$>::Create("
+ "stub_->channel_.get(), "
+ "stub_->rpcmethod_$Method$_, "
+ "context, reactor);\n"
+ "}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
@@ -1577,7 +1870,7 @@ void PrintSourceService(grpc_generator::Printer* printer,
printer->Print(*vars,
"static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) {
- (*vars)["Method"] = service->method(i).get()->name();
+ (*vars)["Method"] = service->method(i)->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
}
printer->Print(*vars, "};\n\n");
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index a923ce8e38..59ddbd82f6 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -609,6 +609,42 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor* service) {
out->Print("\n");
}
+void GenerateBindServiceWithBinderMethod(Printer* out,
+ const ServiceDescriptor* service) {
+ out->Print(
+ "/// <summary>Register service method implementations with a service "
+ "binder. Useful when customizing the service binding logic.\n"
+ "/// Note: this method is part of an experimental API that can change or "
+ "be "
+ "removed without any prior notice.</summary>\n");
+ out->Print(
+ "/// <param name=\"serviceBinder\">Service methods will be bound by "
+ "calling <c>AddMethod</c> on this object."
+ "</param>\n");
+ out->Print(
+ "/// <param name=\"serviceImpl\">An object implementing the server-side"
+ " handling logic.</param>\n");
+ out->Print(
+ "public static void BindService(grpc::ServiceBinderBase serviceBinder, "
+ "$implclass$ "
+ "serviceImpl)\n",
+ "implclass", GetServerClassName(service));
+ out->Print("{\n");
+ out->Indent();
+
+ for (int i = 0; i < service->method_count(); i++) {
+ const MethodDescriptor* method = service->method(i);
+ out->Print(
+ "serviceBinder.AddMethod($methodfield$, serviceImpl.$methodname$);\n",
+ "methodfield", GetMethodFieldName(method), "methodname",
+ method->name());
+ }
+
+ out->Outdent();
+ out->Print("}\n");
+ out->Print("\n");
+}
+
void GenerateService(Printer* out, const ServiceDescriptor* service,
bool generate_client, bool generate_server,
bool internal_access) {
@@ -637,6 +673,7 @@ void GenerateService(Printer* out, const ServiceDescriptor* service,
}
if (generate_server) {
GenerateBindServiceMethod(out, service);
+ GenerateBindServiceWithBinderMethod(out, service);
}
out->Outdent();
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index daf1b89b09..ebc412b468 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -34,9 +34,9 @@
#include "src/core/ext/filters/client_channel/backup_poller.h"
#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
-#include "src/core/ext/filters/client_channel/method_params.h"
#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
#include "src/core/ext/filters/client_channel/retry_throttle.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/deadline/deadline_filter.h"
@@ -63,6 +63,8 @@
#include "src/core/lib/transport/status_metadata.h"
using grpc_core::internal::ClientChannelMethodParams;
+using grpc_core::internal::ClientChannelMethodParamsTable;
+using grpc_core::internal::ProcessedResolverResult;
using grpc_core::internal::ServerRetryThrottleData;
/* Client channel implementation */
@@ -83,10 +85,6 @@ grpc_core::TraceFlag grpc_client_channel_trace(false, "client_channel");
struct external_connectivity_watcher;
-typedef grpc_core::SliceHashTable<
- grpc_core::RefCountedPtr<ClientChannelMethodParams>>
- MethodParamsTable;
-
typedef struct client_channel_channel_data {
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
bool started_resolving;
@@ -102,7 +100,7 @@ typedef struct client_channel_channel_data {
/** retry throttle data */
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
/** maps method names to method_parameters structs */
- grpc_core::RefCountedPtr<MethodParamsTable> method_params_table;
+ grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table;
/** incoming resolver result - set by resolver.next() */
grpc_channel_args* resolver_result;
/** a list of closures that are all waiting for resolver result to come in */
@@ -251,66 +249,6 @@ static void start_resolving_locked(channel_data* chand) {
&chand->on_resolver_result_changed);
}
-typedef struct {
- char* server_name;
- grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
-} service_config_parsing_state;
-
-static void parse_retry_throttle_params(
- const grpc_json* field, service_config_parsing_state* parsing_state) {
- if (strcmp(field->key, "retryThrottling") == 0) {
- if (parsing_state->retry_throttle_data != nullptr) return; // Duplicate.
- if (field->type != GRPC_JSON_OBJECT) return;
- int max_milli_tokens = 0;
- int milli_token_ratio = 0;
- for (grpc_json* sub_field = field->child; sub_field != nullptr;
- sub_field = sub_field->next) {
- if (sub_field->key == nullptr) return;
- if (strcmp(sub_field->key, "maxTokens") == 0) {
- if (max_milli_tokens != 0) return; // Duplicate.
- if (sub_field->type != GRPC_JSON_NUMBER) return;
- max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
- if (max_milli_tokens == -1) return;
- max_milli_tokens *= 1000;
- } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
- if (milli_token_ratio != 0) return; // Duplicate.
- if (sub_field->type != GRPC_JSON_NUMBER) return;
- // We support up to 3 decimal digits.
- size_t whole_len = strlen(sub_field->value);
- uint32_t multiplier = 1;
- uint32_t decimal_value = 0;
- const char* decimal_point = strchr(sub_field->value, '.');
- if (decimal_point != nullptr) {
- whole_len = static_cast<size_t>(decimal_point - sub_field->value);
- multiplier = 1000;
- size_t decimal_len = strlen(decimal_point + 1);
- if (decimal_len > 3) decimal_len = 3;
- if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
- &decimal_value)) {
- return;
- }
- uint32_t decimal_multiplier = 1;
- for (size_t i = 0; i < (3 - decimal_len); ++i) {
- decimal_multiplier *= 10;
- }
- decimal_value *= decimal_multiplier;
- }
- uint32_t whole_value;
- if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
- &whole_value)) {
- return;
- }
- milli_token_ratio =
- static_cast<int>((whole_value * multiplier) + decimal_value);
- if (milli_token_ratio <= 0) return;
- }
- }
- parsing_state->retry_throttle_data =
- grpc_core::internal::ServerRetryThrottleMap::GetDataForServer(
- parsing_state->server_name, max_milli_tokens, milli_token_ratio);
- }
-}
-
// Invoked from the resolver NextLocked() callback when the resolver
// is shutting down.
static void on_resolver_shutdown_locked(channel_data* chand,
@@ -352,37 +290,6 @@ static void on_resolver_shutdown_locked(channel_data* chand,
GRPC_ERROR_UNREF(error);
}
-// Returns the LB policy name from the resolver result.
-static grpc_core::UniquePtr<char>
-get_lb_policy_name_from_resolver_result_locked(channel_data* chand) {
- // Find LB policy name in channel args.
- const grpc_arg* channel_arg =
- grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
- const char* lb_policy_name = grpc_channel_arg_get_string(channel_arg);
- // Special case: If at least one balancer address is present, we use
- // the grpclb policy, regardless of what the resolver actually specified.
- channel_arg =
- grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
- if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
- grpc_lb_addresses* addresses =
- static_cast<grpc_lb_addresses*>(channel_arg->value.pointer.p);
- if (grpc_lb_addresses_contains_balancer_address(*addresses)) {
- if (lb_policy_name != nullptr &&
- gpr_stricmp(lb_policy_name, "grpclb") != 0) {
- gpr_log(GPR_INFO,
- "resolver requested LB policy %s but provided at least one "
- "balancer address -- forcing use of grpclb LB policy",
- lb_policy_name);
- }
- lb_policy_name = "grpclb";
- }
- }
- // Use pick_first if nothing was specified and we didn't select grpclb
- // above.
- if (lb_policy_name == nullptr) lb_policy_name = "pick_first";
- return grpc_core::UniquePtr<char>(gpr_strdup(lb_policy_name));
-}
-
static void request_reresolution_locked(void* arg, grpc_error* error) {
reresolution_request_args* args =
static_cast<reresolution_request_args*>(arg);
@@ -410,13 +317,14 @@ using TraceStringVector = grpc_core::InlinedVector<char*, 3>;
// *connectivity_error to its initial connectivity state; otherwise,
// leaves them unchanged.
static void create_new_lb_policy_locked(
- channel_data* chand, char* lb_policy_name,
+ channel_data* chand, char* lb_policy_name, grpc_json* lb_config,
grpc_connectivity_state* connectivity_state,
grpc_error** connectivity_error, TraceStringVector* trace_strings) {
grpc_core::LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = chand->combiner;
lb_policy_args.client_channel_factory = chand->client_channel_factory;
lb_policy_args.args = chand->resolver_result;
+ lb_policy_args.lb_config = lb_config;
grpc_core::OrphanablePtr<grpc_core::LoadBalancingPolicy> new_lb_policy =
grpc_core::LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
lb_policy_name, lb_policy_args);
@@ -473,44 +381,6 @@ static void create_new_lb_policy_locked(
}
}
-// Returns the service config (as a JSON string) from the resolver result.
-// Also updates state in chand.
-static grpc_core::UniquePtr<char>
-get_service_config_from_resolver_result_locked(channel_data* chand) {
- const grpc_arg* channel_arg =
- grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG);
- const char* service_config_json = grpc_channel_arg_get_string(channel_arg);
- if (service_config_json != nullptr) {
- if (grpc_client_channel_trace.enabled()) {
- gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
- chand, service_config_json);
- }
- grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config =
- grpc_core::ServiceConfig::Create(service_config_json);
- if (service_config != nullptr) {
- if (chand->enable_retries) {
- channel_arg =
- grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVER_URI);
- const char* server_uri = grpc_channel_arg_get_string(channel_arg);
- GPR_ASSERT(server_uri != nullptr);
- grpc_uri* uri = grpc_uri_parse(server_uri, true);
- GPR_ASSERT(uri->path[0] != '\0');
- service_config_parsing_state parsing_state;
- parsing_state.server_name =
- uri->path[0] == '/' ? uri->path + 1 : uri->path;
- service_config->ParseGlobalParams(parse_retry_throttle_params,
- &parsing_state);
- grpc_uri_destroy(uri);
- chand->retry_throttle_data =
- std::move(parsing_state.retry_throttle_data);
- }
- chand->method_params_table = service_config->CreateMethodConfigTable(
- ClientChannelMethodParams::CreateFromJson);
- }
- }
- return grpc_core::UniquePtr<char>(gpr_strdup(service_config_json));
-}
-
static void maybe_add_trace_message_for_address_changes_locked(
channel_data* chand, TraceStringVector* trace_strings) {
int resolution_contains_addresses = false;
@@ -597,36 +467,47 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p: resolver transient failure", chand);
}
+ // Don't override connectivity state if we already have an LB policy.
+ if (chand->lb_policy != nullptr) set_connectivity_state = false;
} else {
+ // Parse the resolver result.
+ ProcessedResolverResult resolver_result(chand->resolver_result,
+ chand->enable_retries);
+ chand->retry_throttle_data = resolver_result.retry_throttle_data();
+ chand->method_params_table = resolver_result.method_params_table();
+ grpc_core::UniquePtr<char> service_config_json =
+ resolver_result.service_config_json();
+ if (service_config_json != nullptr && grpc_client_channel_trace.enabled()) {
+ gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
+ chand, service_config_json.get());
+ }
grpc_core::UniquePtr<char> lb_policy_name =
- get_lb_policy_name_from_resolver_result_locked(chand);
+ resolver_result.lb_policy_name();
+ grpc_json* lb_policy_config = resolver_result.lb_policy_config();
// Check to see if we're already using the right LB policy.
// Note: It's safe to use chand->info_lb_policy_name here without
// taking a lock on chand->info_mu, because this function is the
// only thing that modifies its value, and it can only be invoked
// once at any given time.
- bool lb_policy_name_changed = chand->info_lb_policy_name == nullptr ||
- gpr_stricmp(chand->info_lb_policy_name.get(),
- lb_policy_name.get()) != 0;
+ bool lb_policy_name_changed =
+ chand->info_lb_policy_name == nullptr ||
+ strcmp(chand->info_lb_policy_name.get(), lb_policy_name.get()) != 0;
if (chand->lb_policy != nullptr && !lb_policy_name_changed) {
// Continue using the same LB policy. Update with new addresses.
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p: updating existing LB policy \"%s\" (%p)",
chand, lb_policy_name.get(), chand->lb_policy.get());
}
- chand->lb_policy->UpdateLocked(*chand->resolver_result);
+ chand->lb_policy->UpdateLocked(*chand->resolver_result, lb_policy_config);
// No need to set the channel's connectivity state; the existing
// watch on the LB policy will take care of that.
set_connectivity_state = false;
} else {
// Instantiate new LB policy.
- create_new_lb_policy_locked(chand, lb_policy_name.get(),
+ create_new_lb_policy_locked(chand, lb_policy_name.get(), lb_policy_config,
&connectivity_state, &connectivity_error,
&trace_strings);
}
- // Find service config.
- grpc_core::UniquePtr<char> service_config_json =
- get_service_config_from_resolver_result_locked(chand);
// Note: It's safe to use chand->info_service_config_json here without
// taking a lock on chand->info_mu, because this function is the
// only thing that modifies its value, and it can only be invoked
@@ -689,12 +570,6 @@ static void start_transport_op_locked(void* arg, grpc_error* error_ignored) {
} else {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::LoadBalancingPolicy::PickState pick_state;
- pick_state.initial_metadata = nullptr;
- pick_state.initial_metadata_flags = 0;
- pick_state.on_complete = nullptr;
- memset(&pick_state.subchannel_call_context, 0,
- sizeof(pick_state.subchannel_call_context));
- pick_state.user_data = nullptr;
// Pick must return synchronously, because pick_state.on_complete is null.
GPR_ASSERT(chand->lb_policy->PickLocked(&pick_state, &error));
if (pick_state.connected_subchannel != nullptr) {
@@ -938,12 +813,26 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) {
// (census filter is on top of this one)
// - add census stats for retries
+namespace {
+struct call_data;
+
// State used for starting a retryable batch on a subchannel call.
// This provides its own grpc_transport_stream_op_batch and other data
// structures needed to populate the ops in the batch.
// We allocate one struct on the arena for each attempt at starting a
// batch on a given subchannel call.
-typedef struct {
+struct subchannel_batch_data {
+ subchannel_batch_data(grpc_call_element* elem, call_data* calld, int refcount,
+ bool set_on_complete);
+ // All dtor code must be added in `destroy`. This is because we may
+ // call closures in `subchannel_batch_data` after they are unrefed by
+ // `batch_data_unref`, and msan would complain about accessing this class
+ // after calling dtor. As a result we cannot call the `dtor` in
+ // `batch_data_unref`.
+ // TODO(soheil): We should try to call the dtor in `batch_data_unref`.
+ ~subchannel_batch_data() { destroy(); }
+ void destroy();
+
gpr_refcount refs;
grpc_call_element* elem;
grpc_subchannel_call* subchannel_call; // Holds a ref.
@@ -952,11 +841,23 @@ typedef struct {
grpc_transport_stream_op_batch batch;
// For intercepting on_complete.
grpc_closure on_complete;
-} subchannel_batch_data;
+};
// Retry state associated with a subchannel call.
// Stored in the parent_data of the subchannel call object.
-typedef struct {
+struct subchannel_call_retry_state {
+ explicit subchannel_call_retry_state(grpc_call_context_element* context)
+ : batch_payload(context),
+ started_send_initial_metadata(false),
+ completed_send_initial_metadata(false),
+ started_send_trailing_metadata(false),
+ completed_send_trailing_metadata(false),
+ started_recv_initial_metadata(false),
+ completed_recv_initial_metadata(false),
+ started_recv_trailing_metadata(false),
+ completed_recv_trailing_metadata(false),
+ retry_dispatched(false) {}
+
// subchannel_batch_data.batch.payload points to this.
grpc_transport_stream_op_batch_payload batch_payload;
// For send_initial_metadata.
@@ -975,7 +876,7 @@ typedef struct {
// For intercepting recv_initial_metadata.
grpc_metadata_batch recv_initial_metadata;
grpc_closure recv_initial_metadata_ready;
- bool trailing_metadata_available;
+ bool trailing_metadata_available = false;
// For intercepting recv_message.
grpc_closure recv_message_ready;
grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_message;
@@ -985,10 +886,10 @@ typedef struct {
grpc_closure recv_trailing_metadata_ready;
// These fields indicate which ops have been started and completed on
// this subchannel call.
- size_t started_send_message_count;
- size_t completed_send_message_count;
- size_t started_recv_message_count;
- size_t completed_recv_message_count;
+ size_t started_send_message_count = 0;
+ size_t completed_send_message_count = 0;
+ size_t started_recv_message_count = 0;
+ size_t completed_recv_message_count = 0;
bool started_send_initial_metadata : 1;
bool completed_send_initial_metadata : 1;
bool started_send_trailing_metadata : 1;
@@ -997,14 +898,18 @@ typedef struct {
bool completed_recv_initial_metadata : 1;
bool started_recv_trailing_metadata : 1;
bool completed_recv_trailing_metadata : 1;
+ subchannel_batch_data* recv_initial_metadata_ready_deferred_batch = nullptr;
+ grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+ subchannel_batch_data* recv_message_ready_deferred_batch = nullptr;
+ grpc_error* recv_message_error = GRPC_ERROR_NONE;
+ subchannel_batch_data* recv_trailing_metadata_internal_batch = nullptr;
// State for callback processing.
+ // NOTE: Do not move this next to the metadata bitfields above. That would
+ // save space but will also result in a data race because compiler will
+ // generate a 2 byte store which overwrites the meta-data fields upon
+ // setting this field.
bool retry_dispatched : 1;
- subchannel_batch_data* recv_initial_metadata_ready_deferred_batch;
- grpc_error* recv_initial_metadata_error;
- subchannel_batch_data* recv_message_ready_deferred_batch;
- grpc_error* recv_message_error;
- subchannel_batch_data* recv_trailing_metadata_internal_batch;
-} subchannel_call_retry_state;
+};
// Pending batches stored in call data.
typedef struct {
@@ -1019,7 +924,44 @@ typedef struct {
Handles queueing of stream ops until a call object is ready, waiting
for initial metadata before trying to create a call object,
and handling cancellation gracefully. */
-typedef struct client_channel_call_data {
+struct call_data {
+ call_data(grpc_call_element* elem, const channel_data& chand,
+ const grpc_call_element_args& args)
+ : deadline_state(elem, args.call_stack, args.call_combiner,
+ GPR_LIKELY(chand.deadline_checking_enabled)
+ ? args.deadline
+ : GRPC_MILLIS_INF_FUTURE),
+ path(grpc_slice_ref_internal(args.path)),
+ call_start_time(args.start_time),
+ deadline(args.deadline),
+ arena(args.arena),
+ owning_call(args.call_stack),
+ call_combiner(args.call_combiner),
+ pending_send_initial_metadata(false),
+ pending_send_message(false),
+ pending_send_trailing_metadata(false),
+ enable_retries(chand.enable_retries),
+ retry_committed(false),
+ last_attempt_got_server_pushback(false) {}
+
+ ~call_data() {
+ if (GPR_LIKELY(subchannel_call != nullptr)) {
+ GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call,
+ "client_channel_destroy_call");
+ }
+ grpc_slice_unref_internal(path);
+ GRPC_ERROR_UNREF(cancel_error);
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches); ++i) {
+ GPR_ASSERT(pending_batches[i].batch == nullptr);
+ }
+ for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) {
+ if (pick.subchannel_call_context[i].value != nullptr) {
+ pick.subchannel_call_context[i].destroy(
+ pick.subchannel_call_context[i].value);
+ }
+ }
+ }
+
// State for handling deadlines.
// The code in deadline_filter.c requires this to be the first field.
// TODO(roth): This is slightly sub-optimal in that grpc_deadline_state
@@ -1038,24 +980,24 @@ typedef struct client_channel_call_data {
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
grpc_core::RefCountedPtr<ClientChannelMethodParams> method_params;
- grpc_subchannel_call* subchannel_call;
+ grpc_subchannel_call* subchannel_call = nullptr;
// Set when we get a cancel_stream op.
- grpc_error* cancel_error;
+ grpc_error* cancel_error = GRPC_ERROR_NONE;
grpc_core::LoadBalancingPolicy::PickState pick;
grpc_closure pick_closure;
grpc_closure pick_cancel_closure;
- grpc_polling_entity* pollent;
- bool pollent_added_to_interested_parties;
+ grpc_polling_entity* pollent = nullptr;
+ bool pollent_added_to_interested_parties = false;
// Batches are added to this list when received from above.
// They are removed when we are done handling the batch (i.e., when
// either we have invoked all of the batch's callbacks or we have
// passed the batch down to the subchannel call and are not
// intercepting any of its callbacks).
- pending_batch pending_batches[MAX_PENDING_BATCHES];
+ pending_batch pending_batches[MAX_PENDING_BATCHES] = {};
bool pending_send_initial_metadata : 1;
bool pending_send_message : 1;
bool pending_send_trailing_metadata : 1;
@@ -1064,8 +1006,8 @@ typedef struct client_channel_call_data {
bool enable_retries : 1;
bool retry_committed : 1;
bool last_attempt_got_server_pushback : 1;
- int num_attempts_completed;
- size_t bytes_buffered_for_retry;
+ int num_attempts_completed = 0;
+ size_t bytes_buffered_for_retry = 0;
grpc_core::ManualConstructor<grpc_core::BackOff> retry_backoff;
grpc_timer retry_timer;
@@ -1076,12 +1018,12 @@ typedef struct client_channel_call_data {
// until all of these batches have completed.
// Note that we actually only need to track replay batches, but it's
// easier to track all batches with send ops.
- int num_pending_retriable_subchannel_send_batches;
+ int num_pending_retriable_subchannel_send_batches = 0;
// Cached data for retrying send ops.
// send_initial_metadata
- bool seen_send_initial_metadata;
- grpc_linked_mdelem* send_initial_metadata_storage;
+ bool seen_send_initial_metadata = false;
+ grpc_linked_mdelem* send_initial_metadata_storage = nullptr;
grpc_metadata_batch send_initial_metadata;
uint32_t send_initial_metadata_flags;
gpr_atm* peer_string;
@@ -1092,14 +1034,13 @@ typedef struct client_channel_call_data {
// Note: We inline the cache for the first 3 send_message ops and use
// dynamic allocation after that. This number was essentially picked
// at random; it could be changed in the future to tune performance.
- grpc_core::ManualConstructor<
- grpc_core::InlinedVector<grpc_core::ByteStreamCache*, 3>>
- send_messages;
+ grpc_core::InlinedVector<grpc_core::ByteStreamCache*, 3> send_messages;
// send_trailing_metadata
- bool seen_send_trailing_metadata;
- grpc_linked_mdelem* send_trailing_metadata_storage;
+ bool seen_send_trailing_metadata = false;
+ grpc_linked_mdelem* send_trailing_metadata_storage = nullptr;
grpc_metadata_batch send_trailing_metadata;
-} call_data;
+};
+} // namespace
// Forward declarations.
static void retry_commit(grpc_call_element* elem,
@@ -1143,7 +1084,7 @@ static void maybe_cache_send_ops_for_batch(call_data* calld,
gpr_arena_alloc(calld->arena, sizeof(grpc_core::ByteStreamCache)));
new (cache) grpc_core::ByteStreamCache(
std::move(batch->payload->send_message.send_message));
- calld->send_messages->push_back(cache);
+ calld->send_messages.push_back(cache);
}
// Save metadata batch for send_trailing_metadata ops.
if (batch->send_trailing_metadata) {
@@ -1180,7 +1121,7 @@ static void free_cached_send_message(channel_data* chand, call_data* calld,
"chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR "]",
chand, calld, idx);
}
- (*calld->send_messages)[idx]->Destroy();
+ calld->send_messages[idx]->Destroy();
}
// Frees cached send_trailing_metadata.
@@ -1650,55 +1591,66 @@ static bool maybe_retry(grpc_call_element* elem,
// subchannel_batch_data
//
-// Creates a subchannel_batch_data object on the call's arena with the
-// specified refcount. If set_on_complete is true, the batch's
-// on_complete callback will be set to point to on_complete();
-// otherwise, the batch's on_complete callback will be null.
-static subchannel_batch_data* batch_data_create(grpc_call_element* elem,
- int refcount,
- bool set_on_complete) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
+namespace {
+subchannel_batch_data::subchannel_batch_data(grpc_call_element* elem,
+ call_data* calld, int refcount,
+ bool set_on_complete)
+ : elem(elem),
+ subchannel_call(GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call,
+ "batch_data_create")) {
subchannel_call_retry_state* retry_state =
static_cast<subchannel_call_retry_state*>(
grpc_connected_subchannel_call_get_parent_data(
calld->subchannel_call));
- subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(
- gpr_arena_alloc(calld->arena, sizeof(*batch_data)));
- batch_data->elem = elem;
- batch_data->subchannel_call =
- GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call, "batch_data_create");
- batch_data->batch.payload = &retry_state->batch_payload;
- gpr_ref_init(&batch_data->refs, refcount);
+ batch.payload = &retry_state->batch_payload;
+ gpr_ref_init(&refs, refcount);
if (set_on_complete) {
- GRPC_CLOSURE_INIT(&batch_data->on_complete, on_complete, batch_data,
+ GRPC_CLOSURE_INIT(&on_complete, ::on_complete, this,
grpc_schedule_on_exec_ctx);
- batch_data->batch.on_complete = &batch_data->on_complete;
+ batch.on_complete = &on_complete;
}
GRPC_CALL_STACK_REF(calld->owning_call, "batch_data");
+}
+
+void subchannel_batch_data::destroy() {
+ subchannel_call_retry_state* retry_state =
+ static_cast<subchannel_call_retry_state*>(
+ grpc_connected_subchannel_call_get_parent_data(subchannel_call));
+ if (batch.send_initial_metadata) {
+ grpc_metadata_batch_destroy(&retry_state->send_initial_metadata);
+ }
+ if (batch.send_trailing_metadata) {
+ grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
+ }
+ if (batch.recv_initial_metadata) {
+ grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata);
+ }
+ if (batch.recv_trailing_metadata) {
+ grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata);
+ }
+ GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "batch_data_unref");
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ GRPC_CALL_STACK_UNREF(calld->owning_call, "batch_data");
+}
+} // namespace
+
+// Creates a subchannel_batch_data object on the call's arena with the
+// specified refcount. If set_on_complete is true, the batch's
+// on_complete callback will be set to point to on_complete();
+// otherwise, the batch's on_complete callback will be null.
+static subchannel_batch_data* batch_data_create(grpc_call_element* elem,
+ int refcount,
+ bool set_on_complete) {
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ subchannel_batch_data* batch_data =
+ new (gpr_arena_alloc(calld->arena, sizeof(*batch_data)))
+ subchannel_batch_data(elem, calld, refcount, set_on_complete);
return batch_data;
}
static void batch_data_unref(subchannel_batch_data* batch_data) {
if (gpr_unref(&batch_data->refs)) {
- subchannel_call_retry_state* retry_state =
- static_cast<subchannel_call_retry_state*>(
- grpc_connected_subchannel_call_get_parent_data(
- batch_data->subchannel_call));
- if (batch_data->batch.send_initial_metadata) {
- grpc_metadata_batch_destroy(&retry_state->send_initial_metadata);
- }
- if (batch_data->batch.send_trailing_metadata) {
- grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
- }
- if (batch_data->batch.recv_initial_metadata) {
- grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata);
- }
- if (batch_data->batch.recv_trailing_metadata) {
- grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata);
- }
- GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref");
- call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
- GRPC_CALL_STACK_UNREF(calld->owning_call, "batch_data");
+ batch_data->destroy();
}
}
@@ -1996,7 +1948,7 @@ static bool pending_batch_is_unstarted(
return true;
}
if (pending->batch->send_message &&
- retry_state->started_send_message_count < calld->send_messages->size()) {
+ retry_state->started_send_message_count < calld->send_messages.size()) {
return true;
}
if (pending->batch->send_trailing_metadata &&
@@ -2152,7 +2104,7 @@ static void add_closures_for_replay_or_pending_send_ops(
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
bool have_pending_send_message_ops =
- retry_state->started_send_message_count < calld->send_messages->size();
+ retry_state->started_send_message_count < calld->send_messages.size();
bool have_pending_send_trailing_metadata_op =
calld->seen_send_trailing_metadata &&
!retry_state->started_send_trailing_metadata;
@@ -2344,7 +2296,7 @@ static void add_retriable_send_message_op(
chand, calld, retry_state->started_send_message_count);
}
grpc_core::ByteStreamCache* cache =
- (*calld->send_messages)[retry_state->started_send_message_count];
+ calld->send_messages[retry_state->started_send_message_count];
++retry_state->started_send_message_count;
retry_state->send_message.Init(cache);
batch_data->batch.send_message = true;
@@ -2476,7 +2428,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay(
}
// send_message.
// Note that we can only have one send_message op in flight at a time.
- if (retry_state->started_send_message_count < calld->send_messages->size() &&
+ if (retry_state->started_send_message_count < calld->send_messages.size() &&
retry_state->started_send_message_count ==
retry_state->completed_send_message_count &&
!calld->pending_send_message) {
@@ -2497,7 +2449,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay(
// to start, since we can't send down any more send_message ops after
// send_trailing_metadata.
if (calld->seen_send_trailing_metadata &&
- retry_state->started_send_message_count == calld->send_messages->size() &&
+ retry_state->started_send_message_count == calld->send_messages.size() &&
!retry_state->started_send_trailing_metadata &&
!calld->pending_send_trailing_metadata) {
if (grpc_client_channel_trace.enabled()) {
@@ -2549,7 +2501,7 @@ static void add_subchannel_batches_for_pending_batches(
// send_message ops after send_trailing_metadata.
if (batch->send_trailing_metadata &&
(retry_state->started_send_message_count + batch->send_message <
- calld->send_messages->size() ||
+ calld->send_messages.size() ||
retry_state->started_send_trailing_metadata)) {
continue;
}
@@ -2715,17 +2667,10 @@ static void create_subchannel_call(grpc_call_element* elem, grpc_error* error) {
new_error = grpc_error_add_child(new_error, error);
pending_batches_fail(elem, new_error, true /* yield_call_combiner */);
} else {
- grpc_core::channelz::SubchannelNode* channelz_subchannel =
- calld->pick.connected_subchannel->channelz_subchannel();
- if (channelz_subchannel != nullptr) {
- channelz_subchannel->RecordCallStarted();
- }
if (parent_data_size > 0) {
- subchannel_call_retry_state* retry_state =
- static_cast<subchannel_call_retry_state*>(
- grpc_connected_subchannel_call_get_parent_data(
- calld->subchannel_call));
- retry_state->batch_payload.context = calld->pick.subchannel_call_context;
+ new (grpc_connected_subchannel_call_get_parent_data(
+ calld->subchannel_call))
+ subchannel_call_retry_state(calld->pick.subchannel_call_context);
}
pending_batches_resume(elem);
}
@@ -2951,6 +2896,27 @@ static void apply_service_config_to_call_locked(grpc_call_element* elem) {
}
}
+// If the channel is in TRANSIENT_FAILURE and the call is not
+// wait_for_ready=true, fails the call and returns true.
+static bool fail_call_if_in_transient_failure(grpc_call_element* elem) {
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ grpc_transport_stream_op_batch* batch = calld->pending_batches[0].batch;
+ if (grpc_connectivity_state_check(&chand->state_tracker) ==
+ GRPC_CHANNEL_TRANSIENT_FAILURE &&
+ (batch->payload->send_initial_metadata.send_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
+ pending_batches_fail(
+ elem,
+ grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "channel is in state TRANSIENT_FAILURE"),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
+ true /* yield_call_combiner */);
+ return true;
+ }
+ return false;
+}
+
// Invoked once resolver results are available.
static void process_service_config_and_start_lb_pick_locked(
grpc_call_element* elem) {
@@ -2958,6 +2924,9 @@ static void process_service_config_and_start_lb_pick_locked(
// Only get service config data on the first attempt.
if (GPR_LIKELY(calld->num_attempts_completed == 0)) {
apply_service_config_to_call_locked(elem);
+ // Check this after applying service config, since it may have
+ // affected the call's wait_for_ready value.
+ if (fail_call_if_in_transient_failure(elem)) return;
}
// Start LB pick.
grpc_core::LbPicker::StartLocked(elem);
@@ -3127,6 +3096,16 @@ static void start_pick_locked(void* arg, grpc_error* ignored) {
// We do not yet have an LB policy, so wait for a resolver result.
if (GPR_UNLIKELY(!chand->started_resolving)) {
start_resolving_locked(chand);
+ } else {
+ // Normally, we want to do this check in
+ // process_service_config_and_start_lb_pick_locked(), so that we
+ // can honor the wait_for_ready setting in the service config.
+ // However, if the channel is in TRANSIENT_FAILURE at this point, that
+ // means that the resolver has returned a failure, so we're not going
+ // to get a service config right away. In that case, we fail the
+ // call now based on the wait_for_ready value passed in from the
+ // application.
+ if (fail_call_if_in_transient_failure(elem)) return;
}
// Create a new waiter, which will delete itself when done.
grpc_core::New<grpc_core::ResolverResultWaiter>(elem);
@@ -3231,21 +3210,8 @@ static void cc_start_transport_stream_op_batch(
/* Constructor for call_data */
static grpc_error* cc_init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- // Initialize data members.
- calld->path = grpc_slice_ref_internal(args->path);
- calld->call_start_time = args->start_time;
- calld->deadline = args->deadline;
- calld->arena = args->arena;
- calld->owning_call = args->call_stack;
- calld->call_combiner = args->call_combiner;
- if (GPR_LIKELY(chand->deadline_checking_enabled)) {
- grpc_deadline_state_init(elem, args->call_stack, args->call_combiner,
- calld->deadline);
- }
- calld->enable_retries = chand->enable_retries;
- calld->send_messages.Init();
+ new (elem->call_data) call_data(elem, *chand, *args);
return GRPC_ERROR_NONE;
}
@@ -3254,34 +3220,12 @@ static void cc_destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* then_schedule_closure) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- if (GPR_LIKELY(chand->deadline_checking_enabled)) {
- grpc_deadline_state_destroy(elem);
- }
- grpc_slice_unref_internal(calld->path);
- calld->retry_throttle_data.reset();
- calld->method_params.reset();
- GRPC_ERROR_UNREF(calld->cancel_error);
if (GPR_LIKELY(calld->subchannel_call != nullptr)) {
grpc_subchannel_call_set_cleanup_closure(calld->subchannel_call,
then_schedule_closure);
then_schedule_closure = nullptr;
- GRPC_SUBCHANNEL_CALL_UNREF(calld->subchannel_call,
- "client_channel_destroy_call");
- }
- for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
- GPR_ASSERT(calld->pending_batches[i].batch == nullptr);
- }
- if (GPR_LIKELY(calld->pick.connected_subchannel != nullptr)) {
- calld->pick.connected_subchannel.reset();
- }
- for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) {
- if (calld->pick.subchannel_call_context[i].value != nullptr) {
- calld->pick.subchannel_call_context[i].destroy(
- calld->pick.subchannel_call_context[i].value);
- }
}
- calld->send_messages.Destroy();
+ calld->~call_data();
GRPC_CLOSURE_SCHED(then_schedule_closure, GRPC_ERROR_NONE);
}
diff --git a/src/core/ext/filters/client_channel/health/health_check_client.cc b/src/core/ext/filters/client_channel/health/health_check_client.cc
index 400d99b07c..2232c57120 100644
--- a/src/core/ext/filters/client_channel/health/health_check_client.cc
+++ b/src/core/ext/filters/client_channel/health/health_check_client.cc
@@ -19,6 +19,7 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
+#include <stdio.h>
#include "src/core/ext/filters/client_channel/health/health_check_client.h"
@@ -50,8 +51,7 @@ HealthCheckClient::HealthCheckClient(
RefCountedPtr<ConnectedSubchannel> connected_subchannel,
grpc_pollset_set* interested_parties,
grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode> channelz_node)
- : InternallyRefCountedWithTracing<HealthCheckClient>(
- &grpc_health_check_client_trace),
+ : InternallyRefCounted<HealthCheckClient>(&grpc_health_check_client_trace),
service_name_(service_name),
connected_subchannel_(std::move(connected_subchannel)),
interested_parties_(interested_parties),
@@ -280,15 +280,13 @@ bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error** error) {
HealthCheckClient::CallState::CallState(
RefCountedPtr<HealthCheckClient> health_check_client,
grpc_pollset_set* interested_parties)
- : InternallyRefCountedWithTracing<CallState>(
- &grpc_health_check_client_trace),
+ : InternallyRefCounted<CallState>(&grpc_health_check_client_trace),
health_check_client_(std::move(health_check_client)),
pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)),
arena_(gpr_arena_create(health_check_client_->connected_subchannel_
- ->GetInitialCallSizeEstimate(0))) {
- memset(&call_combiner_, 0, sizeof(call_combiner_));
+ ->GetInitialCallSizeEstimate(0))),
+ payload_(context_) {
grpc_call_combiner_init(&call_combiner_);
- memset(context_, 0, sizeof(context_));
gpr_atm_rel_store(&seen_response_, static_cast<gpr_atm>(0));
}
@@ -298,6 +296,11 @@ HealthCheckClient::CallState::~CallState() {
health_check_client_.get(), this);
}
if (call_ != nullptr) GRPC_SUBCHANNEL_CALL_UNREF(call_, "call_ended");
+ for (size_t i = 0; i < GRPC_CONTEXT_COUNT; i++) {
+ if (context_[i].destroy != nullptr) {
+ context_[i].destroy(context_[i].value);
+ }
+ }
// Unset the call combiner cancellation closure. This has the
// effect of scheduling the previously set cancellation closure, if
// any, so that it can release any internal references it may be
@@ -345,6 +348,7 @@ void HealthCheckClient::CallState::StartCall() {
}
// Initialize payload and batch.
memset(&batch_, 0, sizeof(batch_));
+ payload_.context = context_;
batch_.payload = &payload_;
// on_complete callback takes ref, handled manually.
Ref(DEBUG_LOCATION, "on_complete").release();
diff --git a/src/core/ext/filters/client_channel/health/health_check_client.h b/src/core/ext/filters/client_channel/health/health_check_client.h
index 7f77348f18..2369b73fea 100644
--- a/src/core/ext/filters/client_channel/health/health_check_client.h
+++ b/src/core/ext/filters/client_channel/health/health_check_client.h
@@ -41,8 +41,7 @@
namespace grpc_core {
-class HealthCheckClient
- : public InternallyRefCountedWithTracing<HealthCheckClient> {
+class HealthCheckClient : public InternallyRefCounted<HealthCheckClient> {
public:
HealthCheckClient(const char* service_name,
RefCountedPtr<ConnectedSubchannel> connected_subchannel,
@@ -61,7 +60,7 @@ class HealthCheckClient
private:
// Contains a call to the backend and all the data related to the call.
- class CallState : public InternallyRefCountedWithTracing<CallState> {
+ class CallState : public InternallyRefCounted<CallState> {
public:
CallState(RefCountedPtr<HealthCheckClient> health_check_client,
grpc_pollset_set* interested_parties_);
@@ -97,7 +96,7 @@ class HealthCheckClient
gpr_arena* arena_;
grpc_call_combiner call_combiner_;
- grpc_call_context_element context_[GRPC_CONTEXT_COUNT];
+ grpc_call_context_element context_[GRPC_CONTEXT_COUNT] = {};
// The streaming call to the backend. Always non-NULL.
grpc_subchannel_call* call_;
diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
index bfabc68c66..0716e46818 100644
--- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
@@ -29,7 +29,6 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/gpr/env.h"
@@ -37,6 +36,7 @@
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/uri/uri_parser.h"
typedef struct http_connect_handshaker {
// Base class. Must be first.
diff --git a/src/core/ext/filters/client_channel/http_proxy.cc b/src/core/ext/filters/client_channel/http_proxy.cc
index 26d3f479b7..8951a2920c 100644
--- a/src/core/ext/filters/client_channel/http_proxy.cc
+++ b/src/core/ext/filters/client_channel/http_proxy.cc
@@ -29,12 +29,12 @@
#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/slice/b64.h"
+#include "src/core/lib/uri/uri_parser.h"
/**
* Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the
diff --git a/src/core/ext/filters/client_channel/lb_policy.cc b/src/core/ext/filters/client_channel/lb_policy.cc
index e065f45639..b4e803689e 100644
--- a/src/core/ext/filters/client_channel/lb_policy.cc
+++ b/src/core/ext/filters/client_channel/lb_policy.cc
@@ -27,7 +27,7 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount(
namespace grpc_core {
LoadBalancingPolicy::LoadBalancingPolicy(const Args& args)
- : InternallyRefCountedWithTracing(&grpc_trace_lb_policy_refcount),
+ : InternallyRefCounted(&grpc_trace_lb_policy_refcount),
combiner_(GRPC_COMBINER_REF(args.combiner, "lb_policy")),
client_channel_factory_(args.client_channel_factory),
interested_parties_(grpc_pollset_set_create()),
diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h
index 21f80b7b94..7034da6249 100644
--- a/src/core/ext/filters/client_channel/lb_policy.h
+++ b/src/core/ext/filters/client_channel/lb_policy.h
@@ -42,8 +42,7 @@ namespace grpc_core {
///
/// Any I/O done by the LB policy should be done under the pollset_set
/// returned by \a interested_parties().
-class LoadBalancingPolicy
- : public InternallyRefCountedWithTracing<LoadBalancingPolicy> {
+class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
public:
struct Args {
/// The combiner under which all LB policy calls will be run.
@@ -58,44 +57,47 @@ class LoadBalancingPolicy
/// Note that the LB policy gets the set of addresses from the
/// GRPC_ARG_LB_ADDRESSES channel arg.
grpc_channel_args* args = nullptr;
+ /// Load balancing config from the resolver.
+ grpc_json* lb_config = nullptr;
};
/// State used for an LB pick.
struct PickState {
/// Initial metadata associated with the picking call.
- grpc_metadata_batch* initial_metadata;
+ grpc_metadata_batch* initial_metadata = nullptr;
/// Bitmask used for selective cancelling. See
/// \a CancelMatchingPicksLocked() and \a GRPC_INITIAL_METADATA_* in
/// grpc_types.h.
- uint32_t initial_metadata_flags;
+ uint32_t initial_metadata_flags = 0;
/// Storage for LB token in \a initial_metadata, or nullptr if not used.
grpc_linked_mdelem lb_token_mdelem_storage;
/// Closure to run when pick is complete, if not completed synchronously.
/// If null, pick will fail if a result is not available synchronously.
- grpc_closure* on_complete;
+ grpc_closure* on_complete = nullptr;
/// Will be set to the selected subchannel, or nullptr on failure or when
/// the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
/// Will be populated with context to pass to the subchannel call, if
/// needed.
- grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
+ grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT] = {};
/// Upon success, \a *user_data will be set to whatever opaque information
/// may need to be propagated from the LB policy, or nullptr if not needed.
// TODO(roth): As part of revamping our metadata APIs, try to find a
// way to clean this up and C++-ify it.
- void** user_data;
+ void** user_data = nullptr;
/// Next pointer. For internal use by LB policy.
- PickState* next;
+ PickState* next = nullptr;
};
// Not copyable nor movable.
LoadBalancingPolicy(const LoadBalancingPolicy&) = delete;
LoadBalancingPolicy& operator=(const LoadBalancingPolicy&) = delete;
- /// Updates the policy with a new set of \a args from the resolver.
- /// Note that the LB policy gets the set of addresses from the
+ /// Updates the policy with a new set of \a args and a new \a lb_config from
+ /// the resolver. Note that the LB policy gets the set of addresses from the
/// GRPC_ARG_LB_ADDRESSES channel arg.
- virtual void UpdateLocked(const grpc_channel_args& args) GRPC_ABSTRACT;
+ virtual void UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) GRPC_ABSTRACT;
/// Finds an appropriate subchannel for a call, based on data in \a pick.
/// \a pick must remain alive until the pick is complete.
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
index cc259bcdbf..399bb452f4 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
@@ -37,16 +37,27 @@ static void destroy_channel_elem(grpc_channel_element* elem) {}
namespace {
struct call_data {
+ call_data(const grpc_call_element_args& args) {
+ if (args.context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) {
+ // Get stats object from context and take a ref.
+ client_stats = static_cast<grpc_core::GrpcLbClientStats*>(
+ args.context[GRPC_GRPCLB_CLIENT_STATS].value)
+ ->Ref();
+ // Record call started.
+ client_stats->AddCallStarted();
+ }
+ }
+
// Stats object to update.
grpc_core::RefCountedPtr<grpc_core::GrpcLbClientStats> client_stats;
// State for intercepting send_initial_metadata.
grpc_closure on_complete_for_send;
grpc_closure* original_on_complete_for_send;
- bool send_initial_metadata_succeeded;
+ bool send_initial_metadata_succeeded = false;
// State for intercepting recv_initial_metadata.
grpc_closure recv_initial_metadata_ready;
grpc_closure* original_recv_initial_metadata_ready;
- bool recv_initial_metadata_succeeded;
+ bool recv_initial_metadata_succeeded = false;
};
} // namespace
@@ -70,16 +81,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- // Get stats object from context and take a ref.
GPR_ASSERT(args->context != nullptr);
- if (args->context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) {
- calld->client_stats = static_cast<grpc_core::GrpcLbClientStats*>(
- args->context[GRPC_GRPCLB_CLIENT_STATS].value)
- ->Ref();
- // Record call started.
- calld->client_stats->AddCallStarted();
- }
+ new (elem->call_data) call_data(*args);
return GRPC_ERROR_NONE;
}
@@ -97,6 +100,7 @@ static void destroy_call_elem(grpc_call_element* elem,
// TODO(roth): Eliminate this once filter stack is converted to C++.
calld->client_stats.reset();
}
+ calld->~call_data();
}
static void start_transport_stream_op_batch(
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 17e0d26875..a46579c7f7 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -123,7 +123,8 @@ class GrpcLb : public LoadBalancingPolicy {
public:
GrpcLb(const grpc_lb_addresses* addresses, const Args& args);
- void UpdateLocked(const grpc_channel_args& args) override;
+ void UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) override;
bool PickLocked(PickState* pick, grpc_error** error) override;
void CancelPickLocked(PickState* pick, grpc_error* error) override;
void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
@@ -170,8 +171,7 @@ class GrpcLb : public LoadBalancingPolicy {
};
/// Contains a call to the LB server and all the data related to the call.
- class BalancerCallState
- : public InternallyRefCountedWithTracing<BalancerCallState> {
+ class BalancerCallState : public InternallyRefCounted<BalancerCallState> {
public:
explicit BalancerCallState(
RefCountedPtr<LoadBalancingPolicy> parent_grpclb_policy);
@@ -498,7 +498,7 @@ grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) {
GrpcLb::BalancerCallState::BalancerCallState(
RefCountedPtr<LoadBalancingPolicy> parent_grpclb_policy)
- : InternallyRefCountedWithTracing<BalancerCallState>(&grpc_lb_glb_trace),
+ : InternallyRefCounted<BalancerCallState>(&grpc_lb_glb_trace),
grpclb_policy_(std::move(parent_grpclb_policy)) {
GPR_ASSERT(grpclb_policy_ != nullptr);
GPR_ASSERT(!grpclb_policy()->shutting_down_);
@@ -748,7 +748,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
void* arg, grpc_error* error) {
BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
GrpcLb* grpclb_policy = lb_calld->grpclb_policy();
- // Empty payload means the LB call was cancelled.
+ // Null payload means the LB call was cancelled.
if (lb_calld != grpclb_policy->lb_calld_.get() ||
lb_calld->recv_message_payload_ == nullptr) {
lb_calld->Unref(DEBUG_LOCATION, "on_message_received");
@@ -802,54 +802,45 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
gpr_free(ipport);
}
}
- /* update serverlist */
- if (serverlist->num_servers > 0) {
- // Start sending client load report only after we start using the
- // serverlist returned from the current LB call.
- if (lb_calld->client_stats_report_interval_ > 0 &&
- lb_calld->client_stats_ == nullptr) {
- lb_calld->client_stats_.reset(New<GrpcLbClientStats>());
- // TODO(roth): We currently track this ref manually. Once the
- // ClosureRef API is ready, we should pass the RefCountedPtr<> along
- // with the callback.
- auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report");
- self.release();
- lb_calld->ScheduleNextClientLoadReportLocked();
- }
- if (grpc_grpclb_serverlist_equals(grpclb_policy->serverlist_,
- serverlist)) {
- if (grpc_lb_glb_trace.enabled()) {
- gpr_log(GPR_INFO,
- "[grpclb %p] Incoming server list identical to current, "
- "ignoring.",
- grpclb_policy);
- }
- grpc_grpclb_destroy_serverlist(serverlist);
- } else { /* new serverlist */
- if (grpclb_policy->serverlist_ != nullptr) {
- /* dispose of the old serverlist */
- grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_);
- } else {
- /* or dispose of the fallback */
- grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_);
- grpclb_policy->fallback_backend_addresses_ = nullptr;
- if (grpclb_policy->fallback_timer_callback_pending_) {
- grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_);
- }
- }
- // and update the copy in the GrpcLb instance. This
- // serverlist instance will be destroyed either upon the next
- // update or when the GrpcLb instance is destroyed.
- grpclb_policy->serverlist_ = serverlist;
- grpclb_policy->serverlist_index_ = 0;
- grpclb_policy->CreateOrUpdateRoundRobinPolicyLocked();
- }
- } else {
+ // Start sending client load report only after we start using the
+ // serverlist returned from the current LB call.
+ if (lb_calld->client_stats_report_interval_ > 0 &&
+ lb_calld->client_stats_ == nullptr) {
+ lb_calld->client_stats_.reset(New<GrpcLbClientStats>());
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report");
+ self.release();
+ lb_calld->ScheduleNextClientLoadReportLocked();
+ }
+ // Check if the serverlist differs from the previous one.
+ if (grpc_grpclb_serverlist_equals(grpclb_policy->serverlist_, serverlist)) {
if (grpc_lb_glb_trace.enabled()) {
- gpr_log(GPR_INFO, "[grpclb %p] Received empty server list, ignoring.",
+ gpr_log(GPR_INFO,
+ "[grpclb %p] Incoming server list identical to current, "
+ "ignoring.",
grpclb_policy);
}
grpc_grpclb_destroy_serverlist(serverlist);
+ } else { // New serverlist.
+ if (grpclb_policy->serverlist_ != nullptr) {
+ // Dispose of the old serverlist.
+ grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_);
+ } else {
+ // Dispose of the fallback.
+ grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_);
+ grpclb_policy->fallback_backend_addresses_ = nullptr;
+ if (grpclb_policy->fallback_timer_callback_pending_) {
+ grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_);
+ }
+ }
+ // Update the serverlist in the GrpcLb instance. This serverlist
+ // instance will be destroyed either upon the next update or when the
+ // GrpcLb instance is destroyed.
+ grpclb_policy->serverlist_ = serverlist;
+ grpclb_policy->serverlist_index_ = 0;
+ grpclb_policy->CreateOrUpdateRoundRobinPolicyLocked();
}
} else {
// No valid initial response or serverlist found.
@@ -1331,13 +1322,10 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
grpc_channel_args_destroy(lb_channel_args);
}
-void GrpcLb::UpdateLocked(const grpc_channel_args& args) {
+void GrpcLb::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) {
ProcessChannelArgsLocked(args);
- // If fallback is configured and the RR policy already exists, update
- // it with the new fallback addresses.
- if (lb_fallback_timeout_ms_ > 0 && rr_policy_ != nullptr) {
- CreateOrUpdateRoundRobinPolicyLocked();
- }
+ // Update the existing RR policy.
+ if (rr_policy_ != nullptr) CreateOrUpdateRoundRobinPolicyLocked();
// Start watching the LB channel connectivity for connection, if not
// already doing so.
if (!watching_lb_channel_) {
@@ -1585,7 +1573,7 @@ void GrpcLb::AddPendingPick(PendingPick* pp) {
bool GrpcLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp,
grpc_error** error) {
// Check for drops if we are not using fallback backend addresses.
- if (serverlist_ != nullptr) {
+ if (serverlist_ != nullptr && serverlist_->num_servers > 0) {
// Look at the index into the serverlist to see if we should drop this call.
grpc_grpclb_server* server = serverlist_->servers[serverlist_index_++];
if (serverlist_index_ == serverlist_->num_servers) {
@@ -1683,7 +1671,6 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() {
grpc_lb_addresses* addresses;
bool is_backend_from_grpclb_load_balancer = false;
if (serverlist_ != nullptr) {
- GPR_ASSERT(serverlist_->num_servers > 0);
addresses = ProcessServerlist(serverlist_);
is_backend_from_grpclb_load_balancer = true;
} else {
@@ -1730,7 +1717,7 @@ void GrpcLb::CreateOrUpdateRoundRobinPolicyLocked() {
gpr_log(GPR_INFO, "[grpclb %p] Updating RR policy %p", this,
rr_policy_.get());
}
- rr_policy_->UpdateLocked(*args);
+ rr_policy_->UpdateLocked(*args, nullptr);
} else {
LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = combiner();
diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
index eb494486b9..d1a05f1255 100644
--- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -46,7 +46,8 @@ class PickFirst : public LoadBalancingPolicy {
public:
explicit PickFirst(const Args& args);
- void UpdateLocked(const grpc_channel_args& args) override;
+ void UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) override;
bool PickLocked(PickState* pick, grpc_error** error) override;
void CancelPickLocked(PickState* pick, grpc_error* error) override;
void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
@@ -159,7 +160,7 @@ PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) {
if (grpc_lb_pick_first_trace.enabled()) {
gpr_log(GPR_INFO, "Pick First %p created.", this);
}
- UpdateLocked(*args.args);
+ UpdateLocked(*args.args, args.lb_config);
grpc_subchannel_index_ref();
}
@@ -333,7 +334,8 @@ void PickFirst::UpdateChildRefsLocked() {
child_subchannels_ = std::move(cs);
}
-void PickFirst::UpdateLocked(const grpc_channel_args& args) {
+void PickFirst::UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) {
AutoChildRefsUpdater guard(this);
const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
@@ -378,6 +380,31 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
selected_ = nullptr;
return;
}
+ // If one of the subchannels in the new list is already in state
+ // READY, then select it immediately. This can happen when the
+ // currently selected subchannel is also present in the update. It
+ // can also happen if one of the subchannels in the update is already
+ // in the subchannel index because it's in use by another channel.
+ for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
+ PickFirstSubchannelData* sd = subchannel_list->subchannel(i);
+ grpc_error* error = GRPC_ERROR_NONE;
+ grpc_connectivity_state state = sd->CheckConnectivityStateLocked(&error);
+ GRPC_ERROR_UNREF(error);
+ if (state == GRPC_CHANNEL_READY) {
+ subchannel_list_ = std::move(subchannel_list);
+ sd->ProcessUnselectedReadyLocked();
+ sd->StartConnectivityWatchLocked();
+ // If there was a previously pending update (which may or may
+ // not have contained the currently selected subchannel), drop
+ // it, so that it doesn't override what we've done here.
+ latest_pending_subchannel_list_.reset();
+ // Make sure that subsequent calls to ExitIdleLocked() don't cause
+ // us to start watching a subchannel other than the one we've
+ // selected.
+ started_picking_ = true;
+ return;
+ }
+ }
if (selected_ == nullptr) {
// We don't yet have a selected subchannel, so replace the current
// subchannel list immediately.
@@ -385,46 +412,14 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
// If we've started picking, start trying to connect to the first
// subchannel in the new list.
if (started_picking_) {
- subchannel_list_->subchannel(0)
- ->CheckConnectivityStateAndStartWatchingLocked();
+ // Note: No need to use CheckConnectivityStateAndStartWatchingLocked()
+ // here, since we've already checked the initial connectivity
+ // state of all subchannels above.
+ subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
}
} else {
- // We do have a selected subchannel.
- // Check if it's present in the new list. If so, we're done.
- for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
- PickFirstSubchannelData* sd = subchannel_list->subchannel(i);
- if (sd->subchannel() == selected_->subchannel()) {
- // The currently selected subchannel is in the update: we are done.
- if (grpc_lb_pick_first_trace.enabled()) {
- gpr_log(GPR_INFO,
- "Pick First %p found already selected subchannel %p "
- "at update index %" PRIuPTR " of %" PRIuPTR "; update done",
- this, selected_->subchannel(), i,
- subchannel_list->num_subchannels());
- }
- // Make sure it's in state READY. It might not be if we grabbed
- // the combiner while a connectivity state notification
- // informing us otherwise is pending.
- // Note that CheckConnectivityStateLocked() also takes a ref to
- // the connected subchannel.
- grpc_error* error = GRPC_ERROR_NONE;
- if (sd->CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) {
- selected_ = sd;
- subchannel_list_ = std::move(subchannel_list);
- sd->StartConnectivityWatchLocked();
- // If there was a previously pending update (which may or may
- // not have contained the currently selected subchannel), drop
- // it, so that it doesn't override what we've done here.
- latest_pending_subchannel_list_.reset();
- return;
- }
- GRPC_ERROR_UNREF(error);
- }
- }
- // Not keeping the previous selected subchannel, so set the latest
- // pending subchannel list to the new subchannel list. We will wait
- // for it to report READY before swapping it into the current
- // subchannel list.
+ // We do have a selected subchannel, so keep using it until one of
+ // the subchannels in the new list reports READY.
if (latest_pending_subchannel_list_ != nullptr) {
if (grpc_lb_pick_first_trace.enabled()) {
gpr_log(GPR_INFO,
@@ -438,8 +433,11 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
// If we've started picking, start trying to connect to the first
// subchannel in the new list.
if (started_picking_) {
+ // Note: No need to use CheckConnectivityStateAndStartWatchingLocked()
+ // here, since we've already checked the initial connectivity
+ // state of all subchannels above.
latest_pending_subchannel_list_->subchannel(0)
- ->CheckConnectivityStateAndStartWatchingLocked();
+ ->StartConnectivityWatchLocked();
}
}
}
diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
index e9ed85cf66..2a16975131 100644
--- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
@@ -57,7 +57,8 @@ class RoundRobin : public LoadBalancingPolicy {
public:
explicit RoundRobin(const Args& args);
- void UpdateLocked(const grpc_channel_args& args) override;
+ void UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) override;
bool PickLocked(PickState* pick, grpc_error** error) override;
void CancelPickLocked(PickState* pick, grpc_error* error) override;
void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
@@ -232,7 +233,7 @@ RoundRobin::RoundRobin(const Args& args) : LoadBalancingPolicy(args) {
gpr_mu_init(&child_refs_mu_);
grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
"round_robin");
- UpdateLocked(*args.args);
+ UpdateLocked(*args.args, args.lb_config);
if (grpc_lb_round_robin_trace.enabled()) {
gpr_log(GPR_INFO, "[RR %p] Created with %" PRIuPTR " subchannels", this,
subchannel_list_->num_subchannels());
@@ -664,7 +665,8 @@ void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
notify);
}
-void RoundRobin::UpdateLocked(const grpc_channel_args& args) {
+void RoundRobin::UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) {
const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
AutoChildRefsUpdater guard(this);
if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) {
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
index 4ec9e935ed..f31401502c 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -186,8 +186,7 @@ class SubchannelData {
// A list of subchannels.
template <typename SubchannelListType, typename SubchannelDataType>
-class SubchannelList
- : public InternallyRefCountedWithTracing<SubchannelListType> {
+class SubchannelList : public InternallyRefCounted<SubchannelListType> {
public:
typedef InlinedVector<SubchannelDataType, 10> SubchannelVector;
@@ -226,8 +225,7 @@ class SubchannelList
// Note: Caller must ensure that this is invoked inside of the combiner.
void Orphan() override {
ShutdownLocked();
- InternallyRefCountedWithTracing<SubchannelListType>::Unref(DEBUG_LOCATION,
- "shutdown");
+ InternallyRefCounted<SubchannelListType>::Unref(DEBUG_LOCATION, "shutdown");
}
GRPC_ABSTRACT_BASE_CLASS
@@ -493,7 +491,7 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
const grpc_lb_addresses* addresses, grpc_combiner* combiner,
grpc_client_channel_factory* client_channel_factory,
const grpc_channel_args& args)
- : InternallyRefCountedWithTracing<SubchannelListType>(tracer),
+ : InternallyRefCounted<SubchannelListType>(tracer),
policy_(policy),
tracer_(tracer),
combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) {
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
index 7fb4cbdcd2..faedc0a919 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
@@ -26,30 +26,26 @@
/// channel that uses pick_first to select from the list of balancer
/// addresses.
///
-/// The first time the policy gets a request for a pick, a ping, or to exit
-/// the idle state, \a StartPickingLocked() is called. This method is
-/// responsible for instantiating the internal *streaming* call to the LB
-/// server (whichever address pick_first chose). The call will be complete
-/// when either the balancer sends status or when we cancel the call (e.g.,
-/// because we are shutting down). In needed, we retry the call. If we
-/// received at least one valid message from the server, a new call attempt
-/// will be made immediately; otherwise, we apply back-off delays between
-/// attempts.
+/// The first time the xDS policy gets a request for a pick or to exit the idle
+/// state, \a StartPickingLocked() is called. This method is responsible for
+/// instantiating the internal *streaming* call to the LB server (whichever
+/// address pick_first chose). The call will be complete when either the
+/// balancer sends status or when we cancel the call (e.g., because we are
+/// shutting down). In needed, we retry the call. If we received at least one
+/// valid message from the server, a new call attempt will be made immediately;
+/// otherwise, we apply back-off delays between attempts.
///
-/// We maintain an internal round_robin policy instance for distributing
+/// We maintain an internal child policy (round_robin) instance for distributing
/// requests across backends. Whenever we receive a new serverlist from
-/// the balancer, we update the round_robin policy with the new list of
-/// addresses. If we cannot communicate with the balancer on startup,
-/// however, we may enter fallback mode, in which case we will populate
-/// the RR policy's addresses from the backend addresses returned by the
-/// resolver.
+/// the balancer, we update the child policy with the new list of
+/// addresses.
///
-/// Once an RR policy instance is in place (and getting updated as described),
-/// calls for a pick, a ping, or a cancellation will be serviced right
-/// away by forwarding them to the RR instance. Any time there's no RR
-/// policy available (i.e., right after the creation of the gRPCLB policy),
-/// pick and ping requests are added to a list of pending picks and pings
-/// to be flushed and serviced when the RR policy instance becomes available.
+/// Once a child policy instance is in place (and getting updated as
+/// described), calls for a pick, or a cancellation will be serviced right away
+/// by forwarding them to the child policy instance. Any time there's no child
+/// policy available (i.e., right after the creation of the xDS policy), pick
+/// requests are added to a list of pending picks to be flushed and serviced
+/// when the child policy instance becomes available.
///
/// \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
/// high level design and details.
@@ -122,7 +118,8 @@ class XdsLb : public LoadBalancingPolicy {
public:
XdsLb(const grpc_lb_addresses* addresses, const Args& args);
- void UpdateLocked(const grpc_channel_args& args) override;
+ void UpdateLocked(const grpc_channel_args& args,
+ grpc_json* lb_config) override;
bool PickLocked(PickState* pick, grpc_error** error) override;
void CancelPickLocked(PickState* pick, grpc_error* error) override;
void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
@@ -141,10 +138,10 @@ class XdsLb : public LoadBalancingPolicy {
private:
/// Linked list of pending pick requests. It stores all information needed to
- /// eventually call (Round Robin's) pick() on them. They mainly stay pending
- /// waiting for the RR policy to be created.
+ /// eventually call pick() on them. They mainly stay pending waiting for the
+ /// child policy to be created.
///
- /// Note that when a pick is sent to the RR policy, we inject our own
+ /// Note that when a pick is sent to the child policy, we inject our own
/// on_complete callback, so that we can intercept the result before
/// invoking the original on_complete callback. This allows us to set the
/// LB token metadata and add client_stats to the call context.
@@ -169,8 +166,7 @@ class XdsLb : public LoadBalancingPolicy {
};
/// Contains a call to the LB server and all the data related to the call.
- class BalancerCallState
- : public InternallyRefCountedWithTracing<BalancerCallState> {
+ class BalancerCallState : public InternallyRefCounted<BalancerCallState> {
public:
explicit BalancerCallState(
RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy);
@@ -202,7 +198,6 @@ class XdsLb : public LoadBalancingPolicy {
static bool LoadReportCountersAreZero(xds_grpclb_request* request);
static void MaybeSendClientLoadReportLocked(void* arg, grpc_error* error);
- static void ClientLoadReportDoneLocked(void* arg, grpc_error* error);
static void OnInitialRequestSentLocked(void* arg, grpc_error* error);
static void OnBalancerMessageReceivedLocked(void* arg, grpc_error* error);
static void OnBalancerStatusReceivedLocked(void* arg, grpc_error* error);
@@ -266,18 +261,18 @@ class XdsLb : public LoadBalancingPolicy {
void AddPendingPick(PendingPick* pp);
static void OnPendingPickComplete(void* arg, grpc_error* error);
- // Methods for dealing with the RR policy.
- void CreateOrUpdateRoundRobinPolicyLocked();
- grpc_channel_args* CreateRoundRobinPolicyArgsLocked();
- void CreateRoundRobinPolicyLocked(const Args& args);
- bool PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp,
- grpc_error** error);
- void UpdateConnectivityStateFromRoundRobinPolicyLocked(
- grpc_error* rr_state_error);
- static void OnRoundRobinConnectivityChangedLocked(void* arg,
- grpc_error* error);
- static void OnRoundRobinRequestReresolutionLocked(void* arg,
- grpc_error* error);
+ // Methods for dealing with the child policy.
+ void CreateOrUpdateChildPolicyLocked();
+ grpc_channel_args* CreateChildPolicyArgsLocked();
+ void CreateChildPolicyLocked(const Args& args);
+ bool PickFromChildPolicyLocked(bool force_async, PendingPick* pp,
+ grpc_error** error);
+ void UpdateConnectivityStateFromChildPolicyLocked(
+ grpc_error* child_state_error);
+ static void OnChildPolicyConnectivityChangedLocked(void* arg,
+ grpc_error* error);
+ static void OnChildPolicyRequestReresolutionLocked(void* arg,
+ grpc_error* error);
// Who the client is trying to communicate with.
const char* server_name_ = nullptr;
@@ -319,10 +314,6 @@ class XdsLb : public LoadBalancingPolicy {
// The deserialized response from the balancer. May be nullptr until one
// such response has arrived.
xds_grpclb_serverlist* serverlist_ = nullptr;
- // Index into serverlist for next pick.
- // If the server at this index is a drop, we return a drop.
- // Otherwise, we delegate to the RR policy.
- size_t serverlist_index_ = 0;
// Timeout in milliseconds for before using fallback backend addresses.
// 0 means not using fallback.
@@ -334,14 +325,14 @@ class XdsLb : public LoadBalancingPolicy {
grpc_timer lb_fallback_timer_;
grpc_closure lb_on_fallback_;
- // Pending picks that are waiting on the RR policy's connectivity.
+ // Pending picks that are waiting on the xDS policy's connectivity.
PendingPick* pending_picks_ = nullptr;
- // The RR policy to use for the backends.
- OrphanablePtr<LoadBalancingPolicy> rr_policy_;
- grpc_connectivity_state rr_connectivity_state_;
- grpc_closure on_rr_connectivity_changed_;
- grpc_closure on_rr_request_reresolution_;
+ // The policy to use for the backends.
+ OrphanablePtr<LoadBalancingPolicy> child_policy_;
+ grpc_connectivity_state child_connectivity_state_;
+ grpc_closure on_child_connectivity_changed_;
+ grpc_closure on_child_request_reresolution_;
};
//
@@ -448,7 +439,7 @@ grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) {
grpc_lb_addresses* lb_addresses =
grpc_lb_addresses_create(num_valid, &lb_token_vtable);
/* second pass: actually populate the addresses and LB tokens (aka user data
- * to the outside world) to be read by the RR policy during its creation.
+ * to the outside world) to be read by the child policy during its creation.
* Given that the validity tests are very cheap, they are performed again
* instead of marking the valid ones during the first pass, as this would
* incurr in an allocation due to the arbitrary number of server */
@@ -496,7 +487,7 @@ grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) {
XdsLb::BalancerCallState::BalancerCallState(
RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy)
- : InternallyRefCountedWithTracing<BalancerCallState>(&grpc_lb_xds_trace),
+ : InternallyRefCounted<BalancerCallState>(&grpc_lb_xds_trace),
xdslb_policy_(std::move(parent_xdslb_policy)) {
GPR_ASSERT(xdslb_policy_ != nullptr);
GPR_ASSERT(!xdslb_policy()->shutting_down_);
@@ -675,6 +666,7 @@ bool XdsLb::BalancerCallState::LoadReportCountersAreZero(
(drop_entries == nullptr || drop_entries->empty());
}
+// TODO(vpowar): Use LRS to send the client Load Report.
void XdsLb::BalancerCallState::SendClientLoadReportLocked() {
// Construct message payload.
GPR_ASSERT(send_message_payload_ == nullptr);
@@ -692,38 +684,8 @@ void XdsLb::BalancerCallState::SendClientLoadReportLocked() {
} else {
last_client_load_report_counters_were_zero_ = false;
}
- grpc_slice request_payload_slice = xds_grpclb_request_encode(request);
- send_message_payload_ =
- grpc_raw_byte_buffer_create(&request_payload_slice, 1);
- grpc_slice_unref_internal(request_payload_slice);
+ // TODO(vpowar): Send the report on LRS stream.
xds_grpclb_request_destroy(request);
- // Send the report.
- grpc_op op;
- memset(&op, 0, sizeof(op));
- op.op = GRPC_OP_SEND_MESSAGE;
- op.data.send_message.send_message = send_message_payload_;
- GRPC_CLOSURE_INIT(&client_load_report_closure_, ClientLoadReportDoneLocked,
- this, grpc_combiner_scheduler(xdslb_policy()->combiner()));
- grpc_call_error call_error = grpc_call_start_batch_and_execute(
- lb_call_, &op, 1, &client_load_report_closure_);
- if (GPR_UNLIKELY(call_error != GRPC_CALL_OK)) {
- gpr_log(GPR_ERROR, "[xdslb %p] call_error=%d", xdslb_policy_.get(),
- call_error);
- GPR_ASSERT(GRPC_CALL_OK == call_error);
- }
-}
-
-void XdsLb::BalancerCallState::ClientLoadReportDoneLocked(void* arg,
- grpc_error* error) {
- BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
- XdsLb* xdslb_policy = lb_calld->xdslb_policy();
- grpc_byte_buffer_destroy(lb_calld->send_message_payload_);
- lb_calld->send_message_payload_ = nullptr;
- if (error != GRPC_ERROR_NONE || lb_calld != xdslb_policy->lb_calld_.get()) {
- lb_calld->Unref(DEBUG_LOCATION, "client_load_report");
- return;
- }
- lb_calld->ScheduleNextClientLoadReportLocked();
}
void XdsLb::BalancerCallState::OnInitialRequestSentLocked(void* arg,
@@ -837,8 +799,7 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked(
// serverlist instance will be destroyed either upon the next
// update or when the XdsLb instance is destroyed.
xdslb_policy->serverlist_ = serverlist;
- xdslb_policy->serverlist_index_ = 0;
- xdslb_policy->CreateOrUpdateRoundRobinPolicyLocked();
+ xdslb_policy->CreateOrUpdateChildPolicyLocked();
}
} else {
if (grpc_lb_xds_trace.enabled()) {
@@ -871,7 +832,7 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked(
&lb_calld->lb_on_balancer_message_received_);
GPR_ASSERT(GRPC_CALL_OK == call_error);
} else {
- lb_calld->Unref(DEBUG_LOCATION, "on_message_received+grpclb_shutdown");
+ lb_calld->Unref(DEBUG_LOCATION, "on_message_received+xds_shutdown");
}
}
@@ -949,7 +910,7 @@ grpc_lb_addresses* ExtractBalancerAddresses(
* - \a addresses: corresponding to the balancers.
* - \a response_generator: in order to propagate updates from the resolver
* above the grpclb policy.
- * - \a args: other args inherited from the grpclb policy. */
+ * - \a args: other args inherited from the xds policy. */
grpc_channel_args* BuildBalancerChannelArgs(
const grpc_lb_addresses* addresses,
FakeResolverResponseGenerator* response_generator,
@@ -971,10 +932,10 @@ grpc_channel_args* BuildBalancerChannelArgs(
// resolver will have is_balancer=false, whereas our own addresses have
// is_balancer=true. We need the LB channel to return addresses with
// is_balancer=false so that it does not wind up recursively using the
- // grpclb LB policy, as per the special case logic in client_channel.c.
+ // xds LB policy, as per the special case logic in client_channel.c.
GRPC_ARG_LB_ADDRESSES,
// The fake resolver response generator, because we are replacing it
- // with the one from the grpclb policy, used to propagate updates to
+ // with the one from the xds policy, used to propagate updates to
// the LB channel.
GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
// The LB channel should use the authority indicated by the target
@@ -996,7 +957,7 @@ grpc_channel_args* BuildBalancerChannelArgs(
// address updates into the LB channel.
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator),
- // A channel arg indicating the target is a grpclb load balancer.
+ // A channel arg indicating the target is a xds load balancer.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1),
// A channel arg indicating this is an internal channels, aka it is
@@ -1019,6 +980,7 @@ grpc_channel_args* BuildBalancerChannelArgs(
// ctor and dtor
//
+// TODO(vishalpowar): Use lb_config in args to configure LB policy.
XdsLb::XdsLb(const grpc_lb_addresses* addresses,
const LoadBalancingPolicy::Args& args)
: LoadBalancingPolicy(args),
@@ -1036,11 +998,11 @@ XdsLb::XdsLb(const grpc_lb_addresses* addresses,
GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_,
&XdsLb::OnBalancerChannelConnectivityChangedLocked, this,
grpc_combiner_scheduler(args.combiner));
- GRPC_CLOSURE_INIT(&on_rr_connectivity_changed_,
- &XdsLb::OnRoundRobinConnectivityChangedLocked, this,
+ GRPC_CLOSURE_INIT(&on_child_connectivity_changed_,
+ &XdsLb::OnChildPolicyConnectivityChangedLocked, this,
grpc_combiner_scheduler(args.combiner));
- GRPC_CLOSURE_INIT(&on_rr_request_reresolution_,
- &XdsLb::OnRoundRobinRequestReresolutionLocked, this,
+ GRPC_CLOSURE_INIT(&on_child_request_reresolution_,
+ &XdsLb::OnChildPolicyRequestReresolutionLocked, this,
grpc_combiner_scheduler(args.combiner));
grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, "xds");
// Record server name.
@@ -1092,7 +1054,7 @@ void XdsLb::ShutdownLocked() {
if (fallback_timer_callback_pending_) {
grpc_timer_cancel(&lb_fallback_timer_);
}
- rr_policy_.reset();
+ child_policy_.reset();
TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_CANCELLED);
// We destroy the LB channel here instead of in our destructor because
// destroying the channel triggers a last callback to
@@ -1105,7 +1067,7 @@ void XdsLb::ShutdownLocked() {
gpr_mu_unlock(&lb_channel_mu_);
}
grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
- GRPC_ERROR_REF(error), "grpclb_shutdown");
+ GRPC_ERROR_REF(error), "xds_shutdown");
// Clear pending picks.
PendingPick* pp;
while ((pp = pending_picks_) != nullptr) {
@@ -1138,13 +1100,13 @@ void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
// Cancel a specific pending pick.
//
-// A grpclb pick progresses as follows:
-// - If there's a Round Robin policy (rr_policy_) available, it'll be
-// handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From
-// that point onwards, it'll be RR's responsibility. For cancellations, that
-// implies the pick needs also be cancelled by the RR instance.
-// - Otherwise, without an RR instance, picks stay pending at this policy's
-// level (grpclb), inside the pending_picks_ list. To cancel these,
+// A pick progresses as follows:
+// - If there's a child policy available, it'll be handed over to child policy
+// (in CreateChildPolicyLocked()). From that point onwards, it'll be the
+// child policy's responsibility. For cancellations, that implies the pick
+// needs to be also cancelled by the child policy instance.
+// - Otherwise, without a child policy instance, picks stay pending at this
+// policy's level (xds), inside the pending_picks_ list. To cancel these,
// we invoke the completion closure and set the pick's connected
// subchannel to nullptr right here.
void XdsLb::CancelPickLocked(PickState* pick, grpc_error* error) {
@@ -1164,21 +1126,21 @@ void XdsLb::CancelPickLocked(PickState* pick, grpc_error* error) {
}
pp = next;
}
- if (rr_policy_ != nullptr) {
- rr_policy_->CancelPickLocked(pick, GRPC_ERROR_REF(error));
+ if (child_policy_ != nullptr) {
+ child_policy_->CancelPickLocked(pick, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
// Cancel all pending picks.
//
-// A grpclb pick progresses as follows:
-// - If there's a Round Robin policy (rr_policy_) available, it'll be
-// handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From
-// that point onwards, it'll be RR's responsibility. For cancellations, that
-// implies the pick needs also be cancelled by the RR instance.
-// - Otherwise, without an RR instance, picks stay pending at this policy's
-// level (grpclb), inside the pending_picks_ list. To cancel these,
+// A pick progresses as follows:
+// - If there's a child policy available, it'll be handed over to child policy
+// (in CreateChildPolicyLocked()). From that point onwards, it'll be the
+// child policy's responsibility. For cancellations, that implies the pick
+// needs to be also cancelled by the child policy instance.
+// - Otherwise, without a child policy instance, picks stay pending at this
+// policy's level (xds), inside the pending_picks_ list. To cancel these,
// we invoke the completion closure and set the pick's connected
// subchannel to nullptr right here.
void XdsLb::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
@@ -1200,10 +1162,10 @@ void XdsLb::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
}
pp = next;
}
- if (rr_policy_ != nullptr) {
- rr_policy_->CancelMatchingPicksLocked(initial_metadata_flags_mask,
- initial_metadata_flags_eq,
- GRPC_ERROR_REF(error));
+ if (child_policy_ != nullptr) {
+ child_policy_->CancelMatchingPicksLocked(initial_metadata_flags_mask,
+ initial_metadata_flags_eq,
+ GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
@@ -1218,22 +1180,21 @@ void XdsLb::ResetBackoffLocked() {
if (lb_channel_ != nullptr) {
grpc_channel_reset_connect_backoff(lb_channel_);
}
- if (rr_policy_ != nullptr) {
- rr_policy_->ResetBackoffLocked();
+ if (child_policy_ != nullptr) {
+ child_policy_->ResetBackoffLocked();
}
}
bool XdsLb::PickLocked(PickState* pick, grpc_error** error) {
PendingPick* pp = PendingPickCreate(pick);
bool pick_done = false;
- if (rr_policy_ != nullptr) {
+ if (child_policy_ != nullptr) {
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(GPR_INFO, "[xdslb %p] about to PICK from RR %p", this,
- rr_policy_.get());
+ gpr_log(GPR_INFO, "[xdslb %p] about to PICK from policy %p", this,
+ child_policy_.get());
}
- pick_done =
- PickFromRoundRobinPolicyLocked(false /* force_async */, pp, error);
- } else { // rr_policy_ == NULL
+ pick_done = PickFromChildPolicyLocked(false /* force_async */, pp, error);
+ } else { // child_policy_ == NULL
if (pick->on_complete == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No pick result available but synchronous result required.");
@@ -1241,7 +1202,7 @@ bool XdsLb::PickLocked(PickState* pick, grpc_error** error) {
} else {
if (grpc_lb_xds_trace.enabled()) {
gpr_log(GPR_INFO,
- "[xdslb %p] No RR policy. Adding to grpclb's pending picks",
+ "[xdslb %p] No child policy. Adding to xds's pending picks",
this);
}
AddPendingPick(pp);
@@ -1256,8 +1217,8 @@ bool XdsLb::PickLocked(PickState* pick, grpc_error** error) {
void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
- // delegate to the RoundRobin to fill the children subchannels.
- rr_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
+ // delegate to the child_policy_ to fill the children subchannels.
+ child_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
MutexLock lock(&lb_channel_mu_);
if (lb_channel_ != nullptr) {
grpc_core::channelz::ChannelNode* channel_node =
@@ -1324,13 +1285,15 @@ void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
grpc_channel_args_destroy(lb_channel_args);
}
-void XdsLb::UpdateLocked(const grpc_channel_args& args) {
+// TODO(vishalpowar): Use lb_config to configure LB policy.
+void XdsLb::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) {
ProcessChannelArgsLocked(args);
- // If fallback is configured and the RR policy already exists, update
- // it with the new fallback addresses.
- if (lb_fallback_timeout_ms_ > 0 && rr_policy_ != nullptr) {
- CreateOrUpdateRoundRobinPolicyLocked();
- }
+ // Update the existing child policy.
+ // Note: We have disabled fallback mode in the code, so this child policy must
+ // have been created from a serverlist.
+ // TODO(vpowar): Handle the fallback_address changes when we add support for
+ // fallback in xDS.
+ if (child_policy_ != nullptr) CreateOrUpdateChildPolicyLocked();
// Start watching the LB channel connectivity for connection, if not
// already doing so.
if (!watching_lb_channel_) {
@@ -1398,11 +1361,10 @@ void XdsLb::OnFallbackTimerLocked(void* arg, grpc_error* error) {
if (xdslb_policy->serverlist_ == nullptr && !xdslb_policy->shutting_down_ &&
error == GRPC_ERROR_NONE) {
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(GPR_INFO, "[xdslb %p] Falling back to use backends from resolver",
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Fallback timer fired. Not using fallback backends",
xdslb_policy);
}
- GPR_ASSERT(xdslb_policy->fallback_backend_addresses_ != nullptr);
- xdslb_policy->CreateOrUpdateRoundRobinPolicyLocked();
}
xdslb_policy->Unref(DEBUG_LOCATION, "on_fallback_timer");
}
@@ -1452,8 +1414,8 @@ void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
if (xdslb_policy->shutting_down_) goto done;
// Re-initialize the lb_call. This should also take care of updating the
- // embedded RR policy. Note that the current RR policy, if any, will stay in
- // effect until an update from the new lb_call is received.
+ // child policy. Note that the current child policy, if any, will
+ // stay in effect until an update from the new lb_call is received.
switch (xdslb_policy->lb_channel_connectivity_) {
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_TRANSIENT_FAILURE: {
@@ -1512,8 +1474,8 @@ void DestroyClientStats(void* arg) {
}
void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) {
- /* if connected_subchannel is nullptr, no pick has been made by the RR
- * policy (e.g., all addresses failed to connect). There won't be any
+ /* if connected_subchannel is nullptr, no pick has been made by the
+ * child policy (e.g., all addresses failed to connect). There won't be any
* user_data/token available */
if (pp->pick->connected_subchannel != nullptr) {
if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) {
@@ -1539,8 +1501,8 @@ void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) {
}
/* The \a on_complete closure passed as part of the pick requires keeping a
- * reference to its associated round robin instance. We wrap this closure in
- * order to unref the round robin instance upon its invocation */
+ * reference to its associated child policy instance. We wrap this closure in
+ * order to unref the child policy instance upon its invocation */
void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) {
PendingPick* pp = static_cast<PendingPick*>(arg);
PendingPickSetMetadataAndContext(pp);
@@ -1565,50 +1527,24 @@ void XdsLb::AddPendingPick(PendingPick* pp) {
}
//
-// code for interacting with the RR policy
+// code for interacting with the child policy
//
-// Performs a pick over \a rr_policy_. Given that a pick can return
+// Performs a pick over \a child_policy_. Given that a pick can return
// immediately (ignoring its completion callback), we need to perform the
// cleanups this callback would otherwise be responsible for.
// If \a force_async is true, then we will manually schedule the
// completion callback even if the pick is available immediately.
-bool XdsLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp,
- grpc_error** error) {
- // Check for drops if we are not using fallback backend addresses.
- if (serverlist_ != nullptr) {
- // Look at the index into the serverlist to see if we should drop this call.
- xds_grpclb_server* server = serverlist_->servers[serverlist_index_++];
- if (serverlist_index_ == serverlist_->num_servers) {
- serverlist_index_ = 0; // Wrap-around.
- }
- if (server->drop) {
- // Update client load reporting stats to indicate the number of
- // dropped calls. Note that we have to do this here instead of in
- // the client_load_reporting filter, because we do not create a
- // subchannel call (and therefore no client_load_reporting filter)
- // for dropped calls.
- if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) {
- lb_calld_->client_stats()->AddCallDroppedLocked(
- server->load_balance_token);
- }
- if (force_async) {
- GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE);
- Delete(pp);
- return false;
- }
- Delete(pp);
- return true;
- }
- }
+bool XdsLb::PickFromChildPolicyLocked(bool force_async, PendingPick* pp,
+ grpc_error** error) {
// Set client_stats and user_data.
if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) {
pp->client_stats = lb_calld_->client_stats()->Ref();
}
GPR_ASSERT(pp->pick->user_data == nullptr);
pp->pick->user_data = (void**)&pp->lb_token;
- // Pick via the RR policy.
- bool pick_done = rr_policy_->PickLocked(pp->pick, error);
+ // Pick via the child policy.
+ bool pick_done = child_policy_->PickLocked(pp->pick, error);
if (pick_done) {
PendingPickSetMetadataAndContext(pp);
if (force_async) {
@@ -1619,72 +1555,67 @@ bool XdsLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp,
Delete(pp);
}
// else, the pending pick will be registered and taken care of by the
- // pending pick list inside the RR policy. Eventually,
+ // pending pick list inside the child policy. Eventually,
// OnPendingPickComplete() will be called, which will (among other
// things) add the LB token to the call's initial metadata.
return pick_done;
}
-void XdsLb::CreateRoundRobinPolicyLocked(const Args& args) {
- GPR_ASSERT(rr_policy_ == nullptr);
- rr_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+void XdsLb::CreateChildPolicyLocked(const Args& args) {
+ GPR_ASSERT(child_policy_ == nullptr);
+ child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
"round_robin", args);
- if (GPR_UNLIKELY(rr_policy_ == nullptr)) {
- gpr_log(GPR_ERROR, "[xdslb %p] Failure creating a RoundRobin policy", this);
+ if (GPR_UNLIKELY(child_policy_ == nullptr)) {
+ gpr_log(GPR_ERROR, "[xdslb %p] Failure creating a child policy", this);
return;
}
// TODO(roth): We currently track this ref manually. Once the new
// ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
- auto self = Ref(DEBUG_LOCATION, "on_rr_reresolution_requested");
+ auto self = Ref(DEBUG_LOCATION, "on_child_reresolution_requested");
self.release();
- rr_policy_->SetReresolutionClosureLocked(&on_rr_request_reresolution_);
- grpc_error* rr_state_error = nullptr;
- rr_connectivity_state_ = rr_policy_->CheckConnectivityLocked(&rr_state_error);
- // Connectivity state is a function of the RR policy updated/created.
- UpdateConnectivityStateFromRoundRobinPolicyLocked(rr_state_error);
- // Add the gRPC LB's interested_parties pollset_set to that of the newly
- // created RR policy. This will make the RR policy progress upon activity on
- // gRPC LB, which in turn is tied to the application's call.
- grpc_pollset_set_add_pollset_set(rr_policy_->interested_parties(),
+ child_policy_->SetReresolutionClosureLocked(&on_child_request_reresolution_);
+ grpc_error* child_state_error = nullptr;
+ child_connectivity_state_ =
+ child_policy_->CheckConnectivityLocked(&child_state_error);
+ // Connectivity state is a function of the child policy updated/created.
+ UpdateConnectivityStateFromChildPolicyLocked(child_state_error);
+ // Add the xDS's interested_parties pollset_set to that of the newly created
+ // child policy. This will make the child policy progress upon activity on
+ // xDS LB, which in turn is tied to the application's call.
+ grpc_pollset_set_add_pollset_set(child_policy_->interested_parties(),
interested_parties());
- // Subscribe to changes to the connectivity of the new RR.
+ // Subscribe to changes to the connectivity of the new child policy.
// TODO(roth): We currently track this ref manually. Once the new
// ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
- self = Ref(DEBUG_LOCATION, "on_rr_connectivity_changed");
+ self = Ref(DEBUG_LOCATION, "on_child_connectivity_changed");
self.release();
- rr_policy_->NotifyOnStateChangeLocked(&rr_connectivity_state_,
- &on_rr_connectivity_changed_);
- rr_policy_->ExitIdleLocked();
- // Send pending picks to RR policy.
+ child_policy_->NotifyOnStateChangeLocked(&child_connectivity_state_,
+ &on_child_connectivity_changed_);
+ child_policy_->ExitIdleLocked();
+ // Send pending picks to child policy.
PendingPick* pp;
while ((pp = pending_picks_)) {
pending_picks_ = pp->next;
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(GPR_INFO,
- "[xdslb %p] Pending pick about to (async) PICK from RR %p", this,
- rr_policy_.get());
+ gpr_log(
+ GPR_INFO,
+ "[xdslb %p] Pending pick about to (async) PICK from child policy %p",
+ this, child_policy_.get());
}
grpc_error* error = GRPC_ERROR_NONE;
- PickFromRoundRobinPolicyLocked(true /* force_async */, pp, &error);
+ PickFromChildPolicyLocked(true /* force_async */, pp, &error);
}
}
-grpc_channel_args* XdsLb::CreateRoundRobinPolicyArgsLocked() {
+grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() {
grpc_lb_addresses* addresses;
bool is_backend_from_grpclb_load_balancer = false;
- if (serverlist_ != nullptr) {
- GPR_ASSERT(serverlist_->num_servers > 0);
- addresses = ProcessServerlist(serverlist_);
- is_backend_from_grpclb_load_balancer = true;
- } else {
- // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't
- // received any serverlist from the balancer, we use the fallback backends
- // returned by the resolver. Note that the fallback backend list may be
- // empty, in which case the new round_robin policy will keep the requested
- // picks pending.
- GPR_ASSERT(fallback_backend_addresses_ != nullptr);
- addresses = grpc_lb_addresses_copy(fallback_backend_addresses_);
- }
+ // This should never be invoked if we do not have serverlist_, as fallback
+ // mode is disabled for xDS plugin.
+ GPR_ASSERT(serverlist_ != nullptr);
+ GPR_ASSERT(serverlist_->num_servers > 0);
+ addresses = ProcessServerlist(serverlist_);
+ is_backend_from_grpclb_load_balancer = true;
GPR_ASSERT(addresses != nullptr);
// Replace the LB addresses in the channel args that we pass down to
// the subchannel.
@@ -1704,66 +1635,68 @@ grpc_channel_args* XdsLb::CreateRoundRobinPolicyArgsLocked() {
return args;
}
-void XdsLb::CreateOrUpdateRoundRobinPolicyLocked() {
+void XdsLb::CreateOrUpdateChildPolicyLocked() {
if (shutting_down_) return;
- grpc_channel_args* args = CreateRoundRobinPolicyArgsLocked();
+ grpc_channel_args* args = CreateChildPolicyArgsLocked();
GPR_ASSERT(args != nullptr);
- if (rr_policy_ != nullptr) {
+ if (child_policy_ != nullptr) {
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(GPR_INFO, "[xdslb %p] Updating RR policy %p", this,
- rr_policy_.get());
+ gpr_log(GPR_INFO, "[xdslb %p] Updating the child policy %p", this,
+ child_policy_.get());
}
- rr_policy_->UpdateLocked(*args);
+ // TODO(vishalpowar): Pass the correct LB config.
+ child_policy_->UpdateLocked(*args, nullptr);
} else {
LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = combiner();
lb_policy_args.client_channel_factory = client_channel_factory();
lb_policy_args.args = args;
- CreateRoundRobinPolicyLocked(lb_policy_args);
+ CreateChildPolicyLocked(lb_policy_args);
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(GPR_INFO, "[xdslb %p] Created new RR policy %p", this,
- rr_policy_.get());
+ gpr_log(GPR_INFO, "[xdslb %p] Created a new child policy %p", this,
+ child_policy_.get());
}
}
grpc_channel_args_destroy(args);
}
-void XdsLb::OnRoundRobinRequestReresolutionLocked(void* arg,
- grpc_error* error) {
+void XdsLb::OnChildPolicyRequestReresolutionLocked(void* arg,
+ grpc_error* error) {
XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
if (xdslb_policy->shutting_down_ || error != GRPC_ERROR_NONE) {
- xdslb_policy->Unref(DEBUG_LOCATION, "on_rr_reresolution_requested");
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_child_reresolution_requested");
return;
}
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(
- GPR_INFO,
- "[xdslb %p] Re-resolution requested from the internal RR policy (%p).",
- xdslb_policy, xdslb_policy->rr_policy_.get());
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Re-resolution requested from child policy "
+ "(%p).",
+ xdslb_policy, xdslb_policy->child_policy_.get());
}
// If we are talking to a balancer, we expect to get updated addresses form
- // the balancer, so we can ignore the re-resolution request from the RR
- // policy. Otherwise, handle the re-resolution request using the
- // grpclb policy's original re-resolution closure.
+ // the balancer, so we can ignore the re-resolution request from the child
+ // policy.
+ // Otherwise, handle the re-resolution request using the xds policy's
+ // original re-resolution closure.
if (xdslb_policy->lb_calld_ == nullptr ||
!xdslb_policy->lb_calld_->seen_initial_response()) {
xdslb_policy->TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_NONE);
}
- // Give back the wrapper closure to the RR policy.
- xdslb_policy->rr_policy_->SetReresolutionClosureLocked(
- &xdslb_policy->on_rr_request_reresolution_);
+ // Give back the wrapper closure to the child policy.
+ xdslb_policy->child_policy_->SetReresolutionClosureLocked(
+ &xdslb_policy->on_child_request_reresolution_);
}
-void XdsLb::UpdateConnectivityStateFromRoundRobinPolicyLocked(
- grpc_error* rr_state_error) {
+void XdsLb::UpdateConnectivityStateFromChildPolicyLocked(
+ grpc_error* child_state_error) {
const grpc_connectivity_state curr_glb_state =
grpc_connectivity_state_check(&state_tracker_);
/* The new connectivity status is a function of the previous one and the new
- * input coming from the status of the RR policy.
+ * input coming from the status of the child policy.
*
- * current state (grpclb's)
+ * current state (xds's)
* |
- * v || I | C | R | TF | SD | <- new state (RR's)
+ * v || I | C | R | TF | SD | <- new state (child policy's)
* ===++====+=====+=====+======+======+
* I || I | C | R | [I] | [I] |
* ---++----+-----+-----+------+------+
@@ -1776,52 +1709,51 @@ void XdsLb::UpdateConnectivityStateFromRoundRobinPolicyLocked(
* SD || NA | NA | NA | NA | NA | (*)
* ---++----+-----+-----+------+------+
*
- * A [STATE] indicates that the old RR policy is kept. In those cases, STATE
- * is the current state of grpclb, which is left untouched.
+ * A [STATE] indicates that the old child policy is kept. In those cases,
+ * STATE is the current state of xds, which is left untouched.
*
* In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to
- * the previous RR instance.
+ * the previous child policy instance.
*
* Note that the status is never updated to SHUTDOWN as a result of calling
* this function. Only glb_shutdown() has the power to set that state.
*
* (*) This function mustn't be called during shutting down. */
GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN);
- switch (rr_connectivity_state_) {
+ switch (child_connectivity_state_) {
case GRPC_CHANNEL_TRANSIENT_FAILURE:
case GRPC_CHANNEL_SHUTDOWN:
- GPR_ASSERT(rr_state_error != GRPC_ERROR_NONE);
+ GPR_ASSERT(child_state_error != GRPC_ERROR_NONE);
break;
case GRPC_CHANNEL_IDLE:
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_READY:
- GPR_ASSERT(rr_state_error == GRPC_ERROR_NONE);
+ GPR_ASSERT(child_state_error == GRPC_ERROR_NONE);
}
if (grpc_lb_xds_trace.enabled()) {
- gpr_log(
- GPR_INFO,
- "[xdslb %p] Setting grpclb's state to %s from new RR policy %p state.",
- this, grpc_connectivity_state_name(rr_connectivity_state_),
- rr_policy_.get());
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Setting xds's state to %s from child policy %p state.",
+ this, grpc_connectivity_state_name(child_connectivity_state_),
+ child_policy_.get());
}
- grpc_connectivity_state_set(&state_tracker_, rr_connectivity_state_,
- rr_state_error,
+ grpc_connectivity_state_set(&state_tracker_, child_connectivity_state_,
+ child_state_error,
"update_lb_connectivity_status_locked");
}
-void XdsLb::OnRoundRobinConnectivityChangedLocked(void* arg,
- grpc_error* error) {
+void XdsLb::OnChildPolicyConnectivityChangedLocked(void* arg,
+ grpc_error* error) {
XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
if (xdslb_policy->shutting_down_) {
- xdslb_policy->Unref(DEBUG_LOCATION, "on_rr_connectivity_changed");
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_child_connectivity_changed");
return;
}
- xdslb_policy->UpdateConnectivityStateFromRoundRobinPolicyLocked(
+ xdslb_policy->UpdateConnectivityStateFromChildPolicyLocked(
GRPC_ERROR_REF(error));
- // Resubscribe. Reuse the "on_rr_connectivity_changed" ref.
- xdslb_policy->rr_policy_->NotifyOnStateChangeLocked(
- &xdslb_policy->rr_connectivity_state_,
- &xdslb_policy->on_rr_connectivity_changed_);
+ // Resubscribe. Reuse the "on_child_connectivity_changed" ref.
+ xdslb_policy->child_policy_->NotifyOnStateChangeLocked(
+ &xdslb_policy->child_connectivity_state_,
+ &xdslb_policy->on_child_connectivity_changed_);
}
//
@@ -1848,7 +1780,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
return OrphanablePtr<LoadBalancingPolicy>(New<XdsLb>(addresses, args));
}
- const char* name() const override { return "xds"; }
+ const char* name() const override { return "xds_experimental"; }
};
} // namespace
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h
index 62bdbf2689..a59deadb26 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.h
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -25,7 +25,7 @@
#include "src/core/ext/filters/client_channel/client_channel_factory.h"
#include "src/core/ext/filters/client_channel/lb_policy.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/uri/uri_parser.h"
//
// representation of an LB address
diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.cc b/src/core/ext/filters/client_channel/lb_policy_registry.cc
index d651b1120d..ad459c9c8c 100644
--- a/src/core/ext/filters/client_channel/lb_policy_registry.cc
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.cc
@@ -94,4 +94,9 @@ LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
return factory->CreateLoadBalancingPolicy(args);
}
+bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(const char* name) {
+ GPR_ASSERT(g_state != nullptr);
+ return g_state->GetLoadBalancingPolicyFactory(name) != nullptr;
+}
+
} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.h b/src/core/ext/filters/client_channel/lb_policy_registry.h
index 2e9bb061ed..338f7c9f69 100644
--- a/src/core/ext/filters/client_channel/lb_policy_registry.h
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.h
@@ -47,6 +47,10 @@ class LoadBalancingPolicyRegistry {
/// Creates an LB policy of the type specified by \a name.
static OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
const char* name, const LoadBalancingPolicy::Args& args);
+
+ /// Returns true if the LB policy factory specified by \a name exists in this
+ /// registry.
+ static bool LoadBalancingPolicyExists(const char* name);
};
} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/method_params.cc b/src/core/ext/filters/client_channel/method_params.cc
deleted file mode 100644
index 1f116bb67d..0000000000
--- a/src/core/ext/filters/client_channel/method_params.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/ext/filters/client_channel/method_params.h"
-#include "src/core/lib/channel/status_util.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gprpp/memory.h"
-
-// As per the retry design, we do not allow more than 5 retry attempts.
-#define MAX_MAX_RETRY_ATTEMPTS 5
-
-namespace grpc_core {
-namespace internal {
-
-namespace {
-
-bool ParseWaitForReady(
- grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) {
- if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
- return false;
- }
- *wait_for_ready = field->type == GRPC_JSON_TRUE
- ? ClientChannelMethodParams::WAIT_FOR_READY_TRUE
- : ClientChannelMethodParams::WAIT_FOR_READY_FALSE;
- return true;
-}
-
-// Parses a JSON field of the form generated for a google.proto.Duration
-// proto message, as per:
-// https://developers.google.com/protocol-buffers/docs/proto3#json
-bool ParseDuration(grpc_json* field, grpc_millis* duration) {
- if (field->type != GRPC_JSON_STRING) return false;
- size_t len = strlen(field->value);
- if (field->value[len - 1] != 's') return false;
- UniquePtr<char> buf(gpr_strdup(field->value));
- *(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
- char* decimal_point = strchr(buf.get(), '.');
- int nanos = 0;
- if (decimal_point != nullptr) {
- *decimal_point = '\0';
- nanos = gpr_parse_nonnegative_int(decimal_point + 1);
- if (nanos == -1) {
- return false;
- }
- int num_digits = static_cast<int>(strlen(decimal_point + 1));
- if (num_digits > 9) { // We don't accept greater precision than nanos.
- return false;
- }
- for (int i = 0; i < (9 - num_digits); ++i) {
- nanos *= 10;
- }
- }
- int seconds =
- decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get());
- if (seconds == -1) return false;
- *duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
- return true;
-}
-
-UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
- grpc_json* field) {
- auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>();
- if (field->type != GRPC_JSON_OBJECT) return nullptr;
- for (grpc_json* sub_field = field->child; sub_field != nullptr;
- sub_field = sub_field->next) {
- if (sub_field->key == nullptr) return nullptr;
- if (strcmp(sub_field->key, "maxAttempts") == 0) {
- if (retry_policy->max_attempts != 0) return nullptr; // Duplicate.
- if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
- retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
- if (retry_policy->max_attempts <= 1) return nullptr;
- if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
- gpr_log(GPR_ERROR,
- "service config: clamped retryPolicy.maxAttempts at %d",
- MAX_MAX_RETRY_ATTEMPTS);
- retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
- }
- } else if (strcmp(sub_field->key, "initialBackoff") == 0) {
- if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate.
- if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
- return nullptr;
- }
- if (retry_policy->initial_backoff == 0) return nullptr;
- } else if (strcmp(sub_field->key, "maxBackoff") == 0) {
- if (retry_policy->max_backoff > 0) return nullptr; // Duplicate.
- if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
- return nullptr;
- }
- if (retry_policy->max_backoff == 0) return nullptr;
- } else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
- if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate.
- if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
- if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
- 1) {
- return nullptr;
- }
- if (retry_policy->backoff_multiplier <= 0) return nullptr;
- } else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
- if (!retry_policy->retryable_status_codes.Empty()) {
- return nullptr; // Duplicate.
- }
- if (sub_field->type != GRPC_JSON_ARRAY) return nullptr;
- for (grpc_json* element = sub_field->child; element != nullptr;
- element = element->next) {
- if (element->type != GRPC_JSON_STRING) return nullptr;
- grpc_status_code status;
- if (!grpc_status_code_from_string(element->value, &status)) {
- return nullptr;
- }
- retry_policy->retryable_status_codes.Add(status);
- }
- if (retry_policy->retryable_status_codes.Empty()) return nullptr;
- }
- }
- // Make sure required fields are set.
- if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
- retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 ||
- retry_policy->retryable_status_codes.Empty()) {
- return nullptr;
- }
- return retry_policy;
-}
-
-} // namespace
-
-RefCountedPtr<ClientChannelMethodParams>
-ClientChannelMethodParams::CreateFromJson(const grpc_json* json) {
- RefCountedPtr<ClientChannelMethodParams> method_params =
- MakeRefCounted<ClientChannelMethodParams>();
- for (grpc_json* field = json->child; field != nullptr; field = field->next) {
- if (field->key == nullptr) continue;
- if (strcmp(field->key, "waitForReady") == 0) {
- if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) {
- return nullptr; // Duplicate.
- }
- if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) {
- return nullptr;
- }
- } else if (strcmp(field->key, "timeout") == 0) {
- if (method_params->timeout_ > 0) return nullptr; // Duplicate.
- if (!ParseDuration(field, &method_params->timeout_)) return nullptr;
- } else if (strcmp(field->key, "retryPolicy") == 0) {
- if (method_params->retry_policy_ != nullptr) {
- return nullptr; // Duplicate.
- }
- method_params->retry_policy_ = ParseRetryPolicy(field);
- if (method_params->retry_policy_ == nullptr) return nullptr;
- }
- }
- return method_params;
-}
-
-} // namespace internal
-} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/method_params.h b/src/core/ext/filters/client_channel/method_params.h
deleted file mode 100644
index a31d360f17..0000000000
--- a/src/core/ext/filters/client_channel/method_params.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
-#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/channel/status_util.h"
-#include "src/core/lib/gprpp/ref_counted.h"
-#include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis
-#include "src/core/lib/json/json.h"
-
-namespace grpc_core {
-namespace internal {
-
-class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> {
- public:
- enum WaitForReady {
- WAIT_FOR_READY_UNSET = 0,
- WAIT_FOR_READY_FALSE,
- WAIT_FOR_READY_TRUE
- };
-
- struct RetryPolicy {
- int max_attempts = 0;
- grpc_millis initial_backoff = 0;
- grpc_millis max_backoff = 0;
- float backoff_multiplier = 0;
- StatusCodeSet retryable_status_codes;
- };
-
- /// Creates a method_parameters object from \a json.
- /// Intended for use with ServiceConfig::CreateMethodConfigTable().
- static RefCountedPtr<ClientChannelMethodParams> CreateFromJson(
- const grpc_json* json);
-
- grpc_millis timeout() const { return timeout_; }
- WaitForReady wait_for_ready() const { return wait_for_ready_; }
- const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
-
- private:
- // So New() can call our private ctor.
- template <typename T, typename... Args>
- friend T* grpc_core::New(Args&&... args);
-
- // So Delete() can call our private dtor.
- template <typename T>
- friend void grpc_core::Delete(T*);
-
- ClientChannelMethodParams() {}
- virtual ~ClientChannelMethodParams() {}
-
- grpc_millis timeout_ = 0;
- WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET;
- UniquePtr<RetryPolicy> retry_policy_;
-};
-
-} // namespace internal
-} // namespace grpc_core
-
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H */
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index c2af0e6c49..5c050a2333 100644
--- a/src/core/ext/filters/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -23,8 +23,8 @@
#include <stddef.h>
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/uri/uri_parser.h"
/** Populate \a resolved_addr from \a uri, whose path is expected to contain a
* unix socket path. Returns true upon success. */
diff --git a/src/core/ext/filters/client_channel/resolver.cc b/src/core/ext/filters/client_channel/resolver.cc
index cd11eeb9e4..601b08be24 100644
--- a/src/core/ext/filters/client_channel/resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver.cc
@@ -27,7 +27,7 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount(false,
namespace grpc_core {
Resolver::Resolver(grpc_combiner* combiner)
- : InternallyRefCountedWithTracing(&grpc_trace_resolver_refcount),
+ : InternallyRefCounted(&grpc_trace_resolver_refcount),
combiner_(GRPC_COMBINER_REF(combiner, "resolver")) {}
Resolver::~Resolver() { GRPC_COMBINER_UNREF(combiner_, "resolver"); }
diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
index e9acbb7c41..9da849a101 100644
--- a/src/core/ext/filters/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -44,7 +44,7 @@ namespace grpc_core {
///
/// Note: All methods with a "Locked" suffix must be called from the
/// combiner passed to the constructor.
-class Resolver : public InternallyRefCountedWithTracing<Resolver> {
+class Resolver : public InternallyRefCounted<Resolver> {
public:
// Not copyable nor movable.
Resolver(const Resolver&) = delete;
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 01796ca08f..4ebc2c8161 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -120,6 +120,10 @@ class AresDnsResolver : public Resolver {
grpc_lb_addresses* lb_addresses_ = nullptr;
/// currently resolving service config
char* service_config_json_ = nullptr;
+ // has shutdown been initiated
+ bool shutdown_initiated_ = false;
+ // timeout in milliseconds for active DNS queries
+ int query_timeout_ms_;
};
AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
@@ -157,6 +161,11 @@ AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
grpc_combiner_scheduler(combiner()));
GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this,
grpc_combiner_scheduler(combiner()));
+ const grpc_arg* query_timeout_ms_arg =
+ grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
+ query_timeout_ms_ = grpc_channel_arg_get_integer(
+ query_timeout_ms_arg,
+ {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX});
}
AresDnsResolver::~AresDnsResolver() {
@@ -197,6 +206,7 @@ void AresDnsResolver::ResetBackoffLocked() {
}
void AresDnsResolver::ShutdownLocked() {
+ shutdown_initiated_ = true;
if (have_next_resolution_timer_) {
grpc_timer_cancel(&next_resolution_timer_);
}
@@ -213,9 +223,13 @@ void AresDnsResolver::ShutdownLocked() {
void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
+ GRPC_CARES_TRACE_LOG(
+ "%p re-resolution timer fired. error: %s. shutdown_initiated_: %d", r,
+ grpc_error_string(error), r->shutdown_initiated_);
r->have_next_resolution_timer_ = false;
- if (error == GRPC_ERROR_NONE) {
+ if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) {
if (!r->resolving_) {
+ GRPC_CARES_TRACE_LOG("%p start resolving due to re-resolution timer", r);
r->StartResolvingLocked();
}
}
@@ -301,13 +315,12 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
gpr_free(r->pending_request_);
r->pending_request_ = nullptr;
if (r->lb_addresses_ != nullptr) {
- static const char* args_to_remove[2];
+ static const char* args_to_remove[1];
size_t num_args_to_remove = 0;
- grpc_arg new_args[3];
+ grpc_arg args_to_add[2];
size_t num_args_to_add = 0;
- new_args[num_args_to_add++] =
+ args_to_add[num_args_to_add++] =
grpc_lb_addresses_create_channel_arg(r->lb_addresses_);
- grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config;
char* service_config_string = nullptr;
if (r->service_config_json_ != nullptr) {
service_config_string = ChooseServiceConfig(r->service_config_json_);
@@ -316,31 +329,19 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
gpr_log(GPR_INFO, "selected service config choice: %s",
service_config_string);
args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG;
- new_args[num_args_to_add++] = grpc_channel_arg_string_create(
+ args_to_add[num_args_to_add++] = grpc_channel_arg_string_create(
(char*)GRPC_ARG_SERVICE_CONFIG, service_config_string);
- service_config =
- grpc_core::ServiceConfig::Create(service_config_string);
- if (service_config != nullptr) {
- const char* lb_policy_name =
- service_config->GetLoadBalancingPolicyName();
- if (lb_policy_name != nullptr) {
- args_to_remove[num_args_to_remove++] = GRPC_ARG_LB_POLICY_NAME;
- new_args[num_args_to_add++] = grpc_channel_arg_string_create(
- (char*)GRPC_ARG_LB_POLICY_NAME,
- const_cast<char*>(lb_policy_name));
- }
- }
}
}
result = grpc_channel_args_copy_and_add_and_remove(
- r->channel_args_, args_to_remove, num_args_to_remove, new_args,
+ r->channel_args_, args_to_remove, num_args_to_remove, args_to_add,
num_args_to_add);
gpr_free(service_config_string);
grpc_lb_addresses_destroy(r->lb_addresses_);
// Reset backoff state so that we start from the beginning when the
// next request gets triggered.
r->backoff_.Reset();
- } else {
+ } else if (!r->shutdown_initiated_) {
const char* msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
grpc_millis next_try = r->backoff_.NextAttemptTime();
@@ -416,7 +417,8 @@ void AresDnsResolver::StartResolvingLocked() {
pending_request_ = grpc_dns_lookup_ares_locked(
dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
&on_resolved_, &lb_addresses_, true /* check_grpclb */,
- request_service_config_ ? &service_config_json_ : nullptr, combiner());
+ request_service_config_ ? &service_config_json_ : nullptr,
+ query_timeout_ms_, combiner());
last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
}
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
index fdbd07ebf5..f42b1e309d 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
@@ -33,6 +33,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/timer.h"
typedef struct fd_node {
/** the owner of this fd node */
@@ -76,6 +77,12 @@ struct grpc_ares_ev_driver {
grpc_ares_request* request;
/** Owned by the ev_driver. Creates new GrpcPolledFd's */
grpc_core::UniquePtr<grpc_core::GrpcPolledFdFactory> polled_fd_factory;
+ /** query timeout in milliseconds */
+ int query_timeout_ms;
+ /** alarm to cancel active queries */
+ grpc_timer query_timeout;
+ /** cancels queries on a timeout */
+ grpc_closure on_timeout_locked;
};
static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver);
@@ -116,8 +123,11 @@ static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) {
}
}
+static void on_timeout_locked(void* arg, grpc_error* error);
+
grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
grpc_pollset_set* pollset_set,
+ int query_timeout_ms,
grpc_combiner* combiner,
grpc_ares_request* request) {
*ev_driver = grpc_core::New<grpc_ares_ev_driver>();
@@ -146,6 +156,9 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
grpc_core::NewGrpcPolledFdFactory((*ev_driver)->combiner);
(*ev_driver)
->polled_fd_factory->ConfigureAresChannelLocked((*ev_driver)->channel);
+ GRPC_CLOSURE_INIT(&(*ev_driver)->on_timeout_locked, on_timeout_locked,
+ *ev_driver, grpc_combiner_scheduler(combiner));
+ (*ev_driver)->query_timeout_ms = query_timeout_ms;
return GRPC_ERROR_NONE;
}
@@ -155,6 +168,7 @@ void grpc_ares_ev_driver_on_queries_complete_locked(
// is working, grpc_ares_notify_on_event_locked will shut down the
// fds; if it's not working, there are no fds to shut down.
ev_driver->shutting_down = true;
+ grpc_timer_cancel(&ev_driver->query_timeout);
grpc_ares_ev_driver_unref(ev_driver);
}
@@ -185,6 +199,17 @@ static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) {
return nullptr;
}
+static void on_timeout_locked(void* arg, grpc_error* error) {
+ grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
+ GRPC_CARES_TRACE_LOG(
+ "ev_driver=%p on_timeout_locked. driver->shutting_down=%d. err=%s",
+ driver, driver->shutting_down, grpc_error_string(error));
+ if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
+ grpc_ares_ev_driver_shutdown_locked(driver);
+ }
+ grpc_ares_ev_driver_unref(driver);
+}
+
static void on_readable_locked(void* arg, grpc_error* error) {
fd_node* fdn = static_cast<fd_node*>(arg);
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
@@ -314,6 +339,17 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
if (!ev_driver->working) {
ev_driver->working = true;
grpc_ares_notify_on_event_locked(ev_driver);
+ grpc_millis timeout =
+ ev_driver->query_timeout_ms == 0
+ ? GRPC_MILLIS_INF_FUTURE
+ : ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now();
+ GRPC_CARES_TRACE_LOG(
+ "ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in %" PRId64
+ " ms",
+ ev_driver, timeout);
+ grpc_ares_ev_driver_ref(ev_driver);
+ grpc_timer_init(&ev_driver->query_timeout, timeout,
+ &ev_driver->on_timeout_locked);
}
}
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index 671c537fe7..b8cefd9470 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -43,6 +43,7 @@ ares_channel* grpc_ares_ev_driver_get_channel_locked(
created successfully. */
grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
grpc_pollset_set* pollset_set,
+ int query_timeout_ms,
grpc_combiner* combiner,
grpc_ares_request* request);
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index 582e2203fc..55715869b6 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -359,7 +359,7 @@ done:
void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
grpc_ares_request* r, const char* dns_server, const char* name,
const char* default_port, grpc_pollset_set* interested_parties,
- bool check_grpclb, grpc_combiner* combiner) {
+ bool check_grpclb, int query_timeout_ms, grpc_combiner* combiner) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_ares_hostbyname_request* hr = nullptr;
ares_channel* channel = nullptr;
@@ -388,7 +388,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
port = gpr_strdup(default_port);
}
error = grpc_ares_ev_driver_create_locked(&r->ev_driver, interested_parties,
- combiner, r);
+ query_timeout_ms, combiner, r);
if (error != GRPC_ERROR_NONE) goto error_cleanup;
channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver);
// If dns_server is specified, use it.
@@ -522,7 +522,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout_ms, grpc_combiner* combiner) {
grpc_ares_request* r =
static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
r->ev_driver = nullptr;
@@ -546,7 +546,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
// Look up name using c-ares lib.
grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
r, dns_server, name, default_port, interested_parties, check_grpclb,
- combiner);
+ query_timeout_ms, combiner);
return r;
}
@@ -554,6 +554,7 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+ int query_timeout_ms,
grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {
@@ -648,7 +649,8 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked(
r->ares_request = grpc_dns_lookup_ares_locked(
nullptr /* dns_server */, r->name, r->default_port, r->interested_parties,
&r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */,
- nullptr /* service_config_json */, r->combiner);
+ nullptr /* service_config_json */, GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS,
+ r->combiner);
}
static void grpc_resolve_address_ares_impl(const char* name,
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index a1231cc4e0..9acef1d0ca 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -26,6 +26,8 @@
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#define GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS 10000
+
extern grpc_core::TraceFlag grpc_trace_cares_address_sorting;
extern grpc_core::TraceFlag grpc_trace_cares_resolver;
@@ -60,7 +62,7 @@ extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addresses, bool check_grpclb,
- char** service_config_json, grpc_combiner* combiner);
+ char** service_config_json, int query_timeout_ms, grpc_combiner* combiner);
/* Cancel the pending grpc_ares_request \a request */
extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request);
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
index 9f293c1ac0..fc78b18304 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
@@ -30,7 +30,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout_ms, grpc_combiner* combiner) {
return NULL;
}
@@ -38,6 +38,7 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+ int query_timeout_ms,
grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index 144ac24a56..3aa690bea4 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -103,7 +103,7 @@ void FakeResolver::NextLocked(grpc_channel_args** target_result,
}
void FakeResolver::RequestReresolutionLocked() {
- if (reresolution_results_ != nullptr) {
+ if (reresolution_results_ != nullptr || return_failure_) {
grpc_channel_args_destroy(next_results_);
next_results_ = grpc_channel_args_copy(reresolution_results_);
MaybeFinishNextLocked();
@@ -141,6 +141,7 @@ struct SetResponseClosureArg {
grpc_closure set_response_closure;
FakeResolverResponseGenerator* generator;
grpc_channel_args* response;
+ bool immediate = true;
};
void FakeResolverResponseGenerator::SetResponseLocked(void* arg,
@@ -194,7 +195,7 @@ void FakeResolverResponseGenerator::SetFailureLocked(void* arg,
SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
FakeResolver* resolver = closure_arg->generator->resolver_;
resolver->return_failure_ = true;
- resolver->MaybeFinishNextLocked();
+ if (closure_arg->immediate) resolver->MaybeFinishNextLocked();
Delete(closure_arg);
}
@@ -209,6 +210,18 @@ void FakeResolverResponseGenerator::SetFailure() {
GRPC_ERROR_NONE);
}
+void FakeResolverResponseGenerator::SetFailureOnReresolution() {
+ GPR_ASSERT(resolver_ != nullptr);
+ SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
+ closure_arg->generator = this;
+ closure_arg->immediate = false;
+ GRPC_CLOSURE_SCHED(
+ GRPC_CLOSURE_INIT(&closure_arg->set_response_closure, SetFailureLocked,
+ closure_arg,
+ grpc_combiner_scheduler(resolver_->combiner())),
+ GRPC_ERROR_NONE);
+}
+
namespace {
static void* response_generator_arg_copy(void* p) {
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
index 708eaf1147..7f69059351 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
@@ -20,9 +20,9 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/uri/uri_parser.h"
#define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
"grpc.fake_resolver.response_generator"
@@ -61,6 +61,10 @@ class FakeResolverResponseGenerator
// returning a null result with no error).
void SetFailure();
+ // Same as SetFailure(), but instead of returning the error
+ // immediately, waits for the next call to RequestReresolutionLocked().
+ void SetFailureOnReresolution();
+
// Returns a channel arg containing \a generator.
static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
diff --git a/src/core/ext/filters/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h
index ee3cfeeb9b..d891ef62e1 100644
--- a/src/core/ext/filters/client_channel/resolver_factory.h
+++ b/src/core/ext/filters/client_channel/resolver_factory.h
@@ -24,11 +24,11 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/resolver.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc
new file mode 100644
index 0000000000..4f7fd6b424
--- /dev/null
+++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc
@@ -0,0 +1,369 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+
+// As per the retry design, we do not allow more than 5 retry attempts.
+#define MAX_MAX_RETRY_ATTEMPTS 5
+
+namespace grpc_core {
+namespace internal {
+
+ProcessedResolverResult::ProcessedResolverResult(
+ const grpc_channel_args* resolver_result, bool parse_retry) {
+ ProcessServiceConfig(resolver_result, parse_retry);
+ // If no LB config was found above, just find the LB policy name then.
+ if (lb_policy_name_ == nullptr) ProcessLbPolicyName(resolver_result);
+}
+
+void ProcessedResolverResult::ProcessServiceConfig(
+ const grpc_channel_args* resolver_result, bool parse_retry) {
+ const grpc_arg* channel_arg =
+ grpc_channel_args_find(resolver_result, GRPC_ARG_SERVICE_CONFIG);
+ const char* service_config_json = grpc_channel_arg_get_string(channel_arg);
+ if (service_config_json != nullptr) {
+ service_config_json_.reset(gpr_strdup(service_config_json));
+ service_config_ = grpc_core::ServiceConfig::Create(service_config_json);
+ if (service_config_ != nullptr) {
+ if (parse_retry) {
+ channel_arg =
+ grpc_channel_args_find(resolver_result, GRPC_ARG_SERVER_URI);
+ const char* server_uri = grpc_channel_arg_get_string(channel_arg);
+ GPR_ASSERT(server_uri != nullptr);
+ grpc_uri* uri = grpc_uri_parse(server_uri, true);
+ GPR_ASSERT(uri->path[0] != '\0');
+ server_name_ = uri->path[0] == '/' ? uri->path + 1 : uri->path;
+ service_config_->ParseGlobalParams(ParseServiceConfig, this);
+ grpc_uri_destroy(uri);
+ } else {
+ service_config_->ParseGlobalParams(ParseServiceConfig, this);
+ }
+ method_params_table_ = service_config_->CreateMethodConfigTable(
+ ClientChannelMethodParams::CreateFromJson);
+ }
+ }
+}
+
+void ProcessedResolverResult::ProcessLbPolicyName(
+ const grpc_channel_args* resolver_result) {
+ // Prefer the LB policy name found in the service config. Note that this is
+ // checking the deprecated loadBalancingPolicy field, rather than the new
+ // loadBalancingConfig field.
+ if (service_config_ != nullptr) {
+ lb_policy_name_.reset(
+ gpr_strdup(service_config_->GetLoadBalancingPolicyName()));
+ // Convert to lower-case.
+ if (lb_policy_name_ != nullptr) {
+ char* lb_policy_name = lb_policy_name_.get();
+ for (size_t i = 0; i < strlen(lb_policy_name); ++i) {
+ lb_policy_name[i] = tolower(lb_policy_name[i]);
+ }
+ }
+ }
+ // Otherwise, find the LB policy name set by the client API.
+ if (lb_policy_name_ == nullptr) {
+ const grpc_arg* channel_arg =
+ grpc_channel_args_find(resolver_result, GRPC_ARG_LB_POLICY_NAME);
+ lb_policy_name_.reset(gpr_strdup(grpc_channel_arg_get_string(channel_arg)));
+ }
+ // Special case: If at least one balancer address is present, we use
+ // the grpclb policy, regardless of what the resolver has returned.
+ const grpc_arg* channel_arg =
+ grpc_channel_args_find(resolver_result, GRPC_ARG_LB_ADDRESSES);
+ if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
+ grpc_lb_addresses* addresses =
+ static_cast<grpc_lb_addresses*>(channel_arg->value.pointer.p);
+ if (grpc_lb_addresses_contains_balancer_address(*addresses)) {
+ if (lb_policy_name_ != nullptr &&
+ strcmp(lb_policy_name_.get(), "grpclb") != 0) {
+ gpr_log(GPR_INFO,
+ "resolver requested LB policy %s but provided at least one "
+ "balancer address -- forcing use of grpclb LB policy",
+ lb_policy_name_.get());
+ }
+ lb_policy_name_.reset(gpr_strdup("grpclb"));
+ }
+ }
+ // Use pick_first if nothing was specified and we didn't select grpclb
+ // above.
+ if (lb_policy_name_ == nullptr) {
+ lb_policy_name_.reset(gpr_strdup("pick_first"));
+ }
+}
+
+void ProcessedResolverResult::ParseServiceConfig(
+ const grpc_json* field, ProcessedResolverResult* parsing_state) {
+ parsing_state->ParseLbConfigFromServiceConfig(field);
+ if (parsing_state->server_name_ != nullptr) {
+ parsing_state->ParseRetryThrottleParamsFromServiceConfig(field);
+ }
+}
+
+void ProcessedResolverResult::ParseLbConfigFromServiceConfig(
+ const grpc_json* field) {
+ if (lb_policy_config_ != nullptr) return; // Already found.
+ // Find the LB config global parameter.
+ if (field->key == nullptr || strcmp(field->key, "loadBalancingConfig") != 0 ||
+ field->type != GRPC_JSON_ARRAY) {
+ return; // Not valid lb config array.
+ }
+ // Find the first LB policy that this client supports.
+ for (grpc_json* lb_config = field->child; lb_config != nullptr;
+ lb_config = lb_config->next) {
+ if (lb_config->type != GRPC_JSON_OBJECT) return;
+ // Find the policy object.
+ grpc_json* policy = nullptr;
+ for (grpc_json* field = lb_config->child; field != nullptr;
+ field = field->next) {
+ if (field->key == nullptr || strcmp(field->key, "policy") != 0 ||
+ field->type != GRPC_JSON_OBJECT) {
+ return;
+ }
+ if (policy != nullptr) return; // Duplicate.
+ policy = field;
+ }
+ // Find the specific policy content since the policy object is of type
+ // "oneof".
+ grpc_json* policy_content = nullptr;
+ for (grpc_json* field = policy->child; field != nullptr;
+ field = field->next) {
+ if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) return;
+ if (policy_content != nullptr) return; // Violate "oneof" type.
+ policy_content = field;
+ }
+ // If we support this policy, then select it.
+ if (grpc_core::LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
+ policy_content->key)) {
+ lb_policy_name_.reset(gpr_strdup(policy_content->key));
+ lb_policy_config_ = policy_content->child;
+ return;
+ }
+ }
+}
+
+void ProcessedResolverResult::ParseRetryThrottleParamsFromServiceConfig(
+ const grpc_json* field) {
+ if (strcmp(field->key, "retryThrottling") == 0) {
+ if (retry_throttle_data_ != nullptr) return; // Duplicate.
+ if (field->type != GRPC_JSON_OBJECT) return;
+ int max_milli_tokens = 0;
+ int milli_token_ratio = 0;
+ for (grpc_json* sub_field = field->child; sub_field != nullptr;
+ sub_field = sub_field->next) {
+ if (sub_field->key == nullptr) return;
+ if (strcmp(sub_field->key, "maxTokens") == 0) {
+ if (max_milli_tokens != 0) return; // Duplicate.
+ if (sub_field->type != GRPC_JSON_NUMBER) return;
+ max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
+ if (max_milli_tokens == -1) return;
+ max_milli_tokens *= 1000;
+ } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
+ if (milli_token_ratio != 0) return; // Duplicate.
+ if (sub_field->type != GRPC_JSON_NUMBER) return;
+ // We support up to 3 decimal digits.
+ size_t whole_len = strlen(sub_field->value);
+ uint32_t multiplier = 1;
+ uint32_t decimal_value = 0;
+ const char* decimal_point = strchr(sub_field->value, '.');
+ if (decimal_point != nullptr) {
+ whole_len = static_cast<size_t>(decimal_point - sub_field->value);
+ multiplier = 1000;
+ size_t decimal_len = strlen(decimal_point + 1);
+ if (decimal_len > 3) decimal_len = 3;
+ if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
+ &decimal_value)) {
+ return;
+ }
+ uint32_t decimal_multiplier = 1;
+ for (size_t i = 0; i < (3 - decimal_len); ++i) {
+ decimal_multiplier *= 10;
+ }
+ decimal_value *= decimal_multiplier;
+ }
+ uint32_t whole_value;
+ if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
+ &whole_value)) {
+ return;
+ }
+ milli_token_ratio =
+ static_cast<int>((whole_value * multiplier) + decimal_value);
+ if (milli_token_ratio <= 0) return;
+ }
+ }
+ retry_throttle_data_ =
+ grpc_core::internal::ServerRetryThrottleMap::GetDataForServer(
+ server_name_, max_milli_tokens, milli_token_ratio);
+ }
+}
+
+namespace {
+
+bool ParseWaitForReady(
+ grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) {
+ if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
+ return false;
+ }
+ *wait_for_ready = field->type == GRPC_JSON_TRUE
+ ? ClientChannelMethodParams::WAIT_FOR_READY_TRUE
+ : ClientChannelMethodParams::WAIT_FOR_READY_FALSE;
+ return true;
+}
+
+// Parses a JSON field of the form generated for a google.proto.Duration
+// proto message, as per:
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+bool ParseDuration(grpc_json* field, grpc_millis* duration) {
+ if (field->type != GRPC_JSON_STRING) return false;
+ size_t len = strlen(field->value);
+ if (field->value[len - 1] != 's') return false;
+ UniquePtr<char> buf(gpr_strdup(field->value));
+ *(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
+ char* decimal_point = strchr(buf.get(), '.');
+ int nanos = 0;
+ if (decimal_point != nullptr) {
+ *decimal_point = '\0';
+ nanos = gpr_parse_nonnegative_int(decimal_point + 1);
+ if (nanos == -1) {
+ return false;
+ }
+ int num_digits = static_cast<int>(strlen(decimal_point + 1));
+ if (num_digits > 9) { // We don't accept greater precision than nanos.
+ return false;
+ }
+ for (int i = 0; i < (9 - num_digits); ++i) {
+ nanos *= 10;
+ }
+ }
+ int seconds =
+ decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get());
+ if (seconds == -1) return false;
+ *duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
+ return true;
+}
+
+UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
+ grpc_json* field) {
+ auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>();
+ if (field->type != GRPC_JSON_OBJECT) return nullptr;
+ for (grpc_json* sub_field = field->child; sub_field != nullptr;
+ sub_field = sub_field->next) {
+ if (sub_field->key == nullptr) return nullptr;
+ if (strcmp(sub_field->key, "maxAttempts") == 0) {
+ if (retry_policy->max_attempts != 0) return nullptr; // Duplicate.
+ if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
+ retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
+ if (retry_policy->max_attempts <= 1) return nullptr;
+ if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
+ gpr_log(GPR_ERROR,
+ "service config: clamped retryPolicy.maxAttempts at %d",
+ MAX_MAX_RETRY_ATTEMPTS);
+ retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
+ }
+ } else if (strcmp(sub_field->key, "initialBackoff") == 0) {
+ if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate.
+ if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
+ return nullptr;
+ }
+ if (retry_policy->initial_backoff == 0) return nullptr;
+ } else if (strcmp(sub_field->key, "maxBackoff") == 0) {
+ if (retry_policy->max_backoff > 0) return nullptr; // Duplicate.
+ if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
+ return nullptr;
+ }
+ if (retry_policy->max_backoff == 0) return nullptr;
+ } else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
+ if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate.
+ if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
+ if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
+ 1) {
+ return nullptr;
+ }
+ if (retry_policy->backoff_multiplier <= 0) return nullptr;
+ } else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
+ if (!retry_policy->retryable_status_codes.Empty()) {
+ return nullptr; // Duplicate.
+ }
+ if (sub_field->type != GRPC_JSON_ARRAY) return nullptr;
+ for (grpc_json* element = sub_field->child; element != nullptr;
+ element = element->next) {
+ if (element->type != GRPC_JSON_STRING) return nullptr;
+ grpc_status_code status;
+ if (!grpc_status_code_from_string(element->value, &status)) {
+ return nullptr;
+ }
+ retry_policy->retryable_status_codes.Add(status);
+ }
+ if (retry_policy->retryable_status_codes.Empty()) return nullptr;
+ }
+ }
+ // Make sure required fields are set.
+ if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
+ retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 ||
+ retry_policy->retryable_status_codes.Empty()) {
+ return nullptr;
+ }
+ return retry_policy;
+}
+
+} // namespace
+
+RefCountedPtr<ClientChannelMethodParams>
+ClientChannelMethodParams::CreateFromJson(const grpc_json* json) {
+ RefCountedPtr<ClientChannelMethodParams> method_params =
+ MakeRefCounted<ClientChannelMethodParams>();
+ for (grpc_json* field = json->child; field != nullptr; field = field->next) {
+ if (field->key == nullptr) continue;
+ if (strcmp(field->key, "waitForReady") == 0) {
+ if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) {
+ return nullptr; // Duplicate.
+ }
+ if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) {
+ return nullptr;
+ }
+ } else if (strcmp(field->key, "timeout") == 0) {
+ if (method_params->timeout_ > 0) return nullptr; // Duplicate.
+ if (!ParseDuration(field, &method_params->timeout_)) return nullptr;
+ } else if (strcmp(field->key, "retryPolicy") == 0) {
+ if (method_params->retry_policy_ != nullptr) {
+ return nullptr; // Duplicate.
+ }
+ method_params->retry_policy_ = ParseRetryPolicy(field);
+ if (method_params->retry_policy_ == nullptr) return nullptr;
+ }
+ }
+ return method_params;
+}
+
+} // namespace internal
+} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.h b/src/core/ext/filters/client_channel/resolver_result_parsing.h
new file mode 100644
index 0000000000..f1fb7406bc
--- /dev/null
+++ b/src/core/ext/filters/client_channel/resolver_result_parsing.h
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+#include "src/core/lib/transport/service_config.h"
+
+namespace grpc_core {
+namespace internal {
+
+class ClientChannelMethodParams;
+
+// A table mapping from a method name to its method parameters.
+typedef grpc_core::SliceHashTable<
+ grpc_core::RefCountedPtr<ClientChannelMethodParams>>
+ ClientChannelMethodParamsTable;
+
+// A container of processed fields from the resolver result. Simplifies the
+// usage of resolver result.
+class ProcessedResolverResult {
+ public:
+ // Processes the resolver result and populates the relative members
+ // for later consumption. Tries to parse retry parameters only if parse_retry
+ // is true.
+ ProcessedResolverResult(const grpc_channel_args* resolver_result,
+ bool parse_retry);
+
+ // Getters. Any managed object's ownership is transferred.
+ grpc_core::UniquePtr<char> service_config_json() {
+ return std::move(service_config_json_);
+ }
+ grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data() {
+ return std::move(retry_throttle_data_);
+ }
+ grpc_core::RefCountedPtr<ClientChannelMethodParamsTable>
+ method_params_table() {
+ return std::move(method_params_table_);
+ }
+ grpc_core::UniquePtr<char> lb_policy_name() {
+ return std::move(lb_policy_name_);
+ }
+ grpc_json* lb_policy_config() { return lb_policy_config_; }
+
+ private:
+ // Finds the service config; extracts LB config and (maybe) retry throttle
+ // params from it.
+ void ProcessServiceConfig(const grpc_channel_args* resolver_result,
+ bool parse_retry);
+
+ // Finds the LB policy name (when no LB config was found).
+ void ProcessLbPolicyName(const grpc_channel_args* resolver_result);
+
+ // Parses the service config. Intended to be used by
+ // ServiceConfig::ParseGlobalParams.
+ static void ParseServiceConfig(const grpc_json* field,
+ ProcessedResolverResult* parsing_state);
+ // Parses the LB config from service config.
+ void ParseLbConfigFromServiceConfig(const grpc_json* field);
+ // Parses the retry throttle parameters from service config.
+ void ParseRetryThrottleParamsFromServiceConfig(const grpc_json* field);
+
+ // Service config.
+ grpc_core::UniquePtr<char> service_config_json_;
+ grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config_;
+ // LB policy.
+ grpc_json* lb_policy_config_ = nullptr;
+ grpc_core::UniquePtr<char> lb_policy_name_;
+ // Retry throttle data.
+ char* server_name_ = nullptr;
+ grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+ // Method params table.
+ grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
+};
+
+// The parameters of a method.
+class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> {
+ public:
+ enum WaitForReady {
+ WAIT_FOR_READY_UNSET = 0,
+ WAIT_FOR_READY_FALSE,
+ WAIT_FOR_READY_TRUE
+ };
+
+ struct RetryPolicy {
+ int max_attempts = 0;
+ grpc_millis initial_backoff = 0;
+ grpc_millis max_backoff = 0;
+ float backoff_multiplier = 0;
+ StatusCodeSet retryable_status_codes;
+ };
+
+ /// Creates a method_parameters object from \a json.
+ /// Intended for use with ServiceConfig::CreateMethodConfigTable().
+ static RefCountedPtr<ClientChannelMethodParams> CreateFromJson(
+ const grpc_json* json);
+
+ grpc_millis timeout() const { return timeout_; }
+ WaitForReady wait_for_ready() const { return wait_for_ready_; }
+ const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
+
+ private:
+ // So New() can call our private ctor.
+ template <typename T, typename... Args>
+ friend T* grpc_core::New(Args&&... args);
+
+ // So Delete() can call our private dtor.
+ template <typename T>
+ friend void grpc_core::Delete(T*);
+
+ ClientChannelMethodParams() {}
+ virtual ~ClientChannelMethodParams() {}
+
+ grpc_millis timeout_ = 0;
+ WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET;
+ UniquePtr<RetryPolicy> retry_policy_;
+};
+
+} // namespace internal
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H */
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index e4c6efe862..af55f7710e 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -34,7 +34,6 @@
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/filters/client_channel/subchannel_index.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
@@ -54,6 +53,7 @@
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/service_config.h"
#include "src/core/lib/transport/status_metadata.h"
+#include "src/core/lib/uri/uri_parser.h"
#define INTERNAL_REF_BITS 16
#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
@@ -153,7 +153,7 @@ struct grpc_subchannel {
/** have we started the backoff loop */
bool backoff_begun;
// reset_backoff() was called while alarm was pending
- bool deferred_reset_backoff;
+ bool retry_immediately;
/** our alarm */
grpc_timer alarm;
@@ -162,12 +162,16 @@ struct grpc_subchannel {
};
struct grpc_subchannel_call {
+ grpc_subchannel_call(grpc_core::ConnectedSubchannel* connection,
+ const grpc_core::ConnectedSubchannel::CallArgs& args)
+ : connection(connection), deadline(args.deadline) {}
+
grpc_core::ConnectedSubchannel* connection;
- grpc_closure* schedule_closure_after_destroy;
+ grpc_closure* schedule_closure_after_destroy = nullptr;
// state needed to support channelz interception of recv trailing metadata.
grpc_closure recv_trailing_metadata_ready;
grpc_closure* original_recv_trailing_metadata;
- grpc_metadata_batch* recv_trailing_metadata;
+ grpc_metadata_batch* recv_trailing_metadata = nullptr;
grpc_millis deadline;
};
@@ -705,8 +709,8 @@ static void on_alarm(void* arg, grpc_error* error) {
if (c->disconnected) {
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected",
&error, 1);
- } else if (c->deferred_reset_backoff) {
- c->deferred_reset_backoff = false;
+ } else if (c->retry_immediately) {
+ c->retry_immediately = false;
error = GRPC_ERROR_NONE;
} else {
GRPC_ERROR_REF(error);
@@ -883,12 +887,12 @@ static void on_subchannel_connected(void* arg, grpc_error* error) {
void grpc_subchannel_reset_backoff(grpc_subchannel* subchannel) {
gpr_mu_lock(&subchannel->mu);
+ subchannel->backoff->Reset();
if (subchannel->have_alarm) {
- subchannel->deferred_reset_backoff = true;
+ subchannel->retry_immediately = true;
grpc_timer_cancel(&subchannel->alarm);
} else {
subchannel->backoff_begun = false;
- subchannel->backoff->Reset();
maybe_start_connecting_locked(subchannel);
}
gpr_mu_unlock(&subchannel->mu);
@@ -905,6 +909,7 @@ static void subchannel_call_destroy(void* call, grpc_error* error) {
grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c), nullptr,
c->schedule_closure_after_destroy);
connection->Unref(DEBUG_LOCATION, "subchannel_call");
+ c->~grpc_subchannel_call();
}
void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call* call,
@@ -1067,7 +1072,7 @@ ConnectedSubchannel::ConnectedSubchannel(
grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode>
channelz_subchannel,
intptr_t socket_uuid)
- : RefCountedWithTracing<ConnectedSubchannel>(&grpc_trace_stream_refcount),
+ : RefCounted<ConnectedSubchannel>(&grpc_trace_stream_refcount),
channel_stack_(channel_stack),
channelz_subchannel_(std::move(channelz_subchannel)),
socket_uuid_(socket_uuid) {}
@@ -1102,14 +1107,12 @@ grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
grpc_subchannel_call** call) {
const size_t allocation_size =
GetInitialCallSizeEstimate(args.parent_data_size);
- *call = static_cast<grpc_subchannel_call*>(
- gpr_arena_alloc(args.arena, allocation_size));
+ *call = new (gpr_arena_alloc(args.arena, allocation_size))
+ grpc_subchannel_call(this, args);
grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
RefCountedPtr<ConnectedSubchannel> connection =
Ref(DEBUG_LOCATION, "subchannel_call");
connection.release(); // Ref is passed to the grpc_subchannel_call object.
- (*call)->connection = this;
- (*call)->deadline = args.deadline;
const grpc_call_element_args call_args = {
callstk, /* call_stack */
nullptr, /* server_transport_data */
@@ -1128,6 +1131,9 @@ grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
return error;
}
grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent);
+ if (channelz_subchannel_ != nullptr) {
+ channelz_subchannel_->RecordCallStarted();
+ }
return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
index ec3b4d86e4..69c2456ec2 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -72,7 +72,7 @@ typedef struct grpc_subchannel_key grpc_subchannel_key;
namespace grpc_core {
-class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> {
+class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
public:
struct CallArgs {
grpc_polling_entity* pollent;
diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc
index 1c23a6c4be..aa8441f17b 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.cc
+++ b/src/core/ext/filters/client_channel/subchannel_index.cc
@@ -91,7 +91,7 @@ void grpc_subchannel_key_destroy(grpc_subchannel_key* k) {
gpr_free(k);
}
-static void sck_avl_destroy(void* p, void* user_data) {
+static void sck_avl_destroy(void* p, void* unused) {
grpc_subchannel_key_destroy(static_cast<grpc_subchannel_key*>(p));
}
@@ -104,7 +104,7 @@ static long sck_avl_compare(void* a, void* b, void* unused) {
static_cast<grpc_subchannel_key*>(b));
}
-static void scv_avl_destroy(void* p, void* user_data) {
+static void scv_avl_destroy(void* p, void* unused) {
GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "subchannel_index");
}
@@ -137,7 +137,7 @@ void grpc_subchannel_index_shutdown(void) {
void grpc_subchannel_index_unref(void) {
if (gpr_unref(&g_refcount)) {
gpr_mu_destroy(&g_mu);
- grpc_avl_unref(g_subchannel_index, grpc_core::ExecCtx::Get());
+ grpc_avl_unref(g_subchannel_index, nullptr);
}
}
@@ -147,13 +147,12 @@ grpc_subchannel* grpc_subchannel_index_find(grpc_subchannel_key* key) {
// Lock, and take a reference to the subchannel index.
// We don't need to do the search under a lock as avl's are immutable.
gpr_mu_lock(&g_mu);
- grpc_avl index = grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+ grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
gpr_mu_unlock(&g_mu);
grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
- (grpc_subchannel*)grpc_avl_get(index, key, grpc_core::ExecCtx::Get()),
- "index_find");
- grpc_avl_unref(index, grpc_core::ExecCtx::Get());
+ (grpc_subchannel*)grpc_avl_get(index, key, nullptr), "index_find");
+ grpc_avl_unref(index, nullptr);
return c;
}
@@ -169,13 +168,11 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key,
// Compare and swap loop:
// - take a reference to the current index
gpr_mu_lock(&g_mu);
- grpc_avl index =
- grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+ grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
gpr_mu_unlock(&g_mu);
// - Check to see if a subchannel already exists
- c = static_cast<grpc_subchannel*>(
- grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
+ c = static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr));
if (c != nullptr) {
c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
}
@@ -184,11 +181,9 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key,
need_to_unref_constructed = true;
} else {
// no -> update the avl and compare/swap
- grpc_avl updated =
- grpc_avl_add(grpc_avl_ref(index, grpc_core::ExecCtx::Get()),
- subchannel_key_copy(key),
- GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"),
- grpc_core::ExecCtx::Get());
+ grpc_avl updated = grpc_avl_add(
+ grpc_avl_ref(index, nullptr), subchannel_key_copy(key),
+ GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), nullptr);
// it may happen (but it's expected to be unlikely)
// that some other thread has changed the index:
@@ -200,9 +195,9 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key,
}
gpr_mu_unlock(&g_mu);
- grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
+ grpc_avl_unref(updated, nullptr);
}
- grpc_avl_unref(index, grpc_core::ExecCtx::Get());
+ grpc_avl_unref(index, nullptr);
}
if (need_to_unref_constructed) {
@@ -219,24 +214,22 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
// Compare and swap loop:
// - take a reference to the current index
gpr_mu_lock(&g_mu);
- grpc_avl index =
- grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+ grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
gpr_mu_unlock(&g_mu);
// Check to see if this key still refers to the previously
// registered subchannel
- grpc_subchannel* c = static_cast<grpc_subchannel*>(
- grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
+ grpc_subchannel* c =
+ static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr));
if (c != constructed) {
- grpc_avl_unref(index, grpc_core::ExecCtx::Get());
+ grpc_avl_unref(index, nullptr);
break;
}
// compare and swap the update (some other thread may have
// mutated the index behind us)
grpc_avl updated =
- grpc_avl_remove(grpc_avl_ref(index, grpc_core::ExecCtx::Get()), key,
- grpc_core::ExecCtx::Get());
+ grpc_avl_remove(grpc_avl_ref(index, nullptr), key, nullptr);
gpr_mu_lock(&g_mu);
if (index.root == g_subchannel_index.root) {
@@ -245,8 +238,8 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
}
gpr_mu_unlock(&g_mu);
- grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
- grpc_avl_unref(index, grpc_core::ExecCtx::Get());
+ grpc_avl_unref(updated, nullptr);
+ grpc_avl_unref(index, nullptr);
}
}
diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc
index d23ad67ad5..b4cb07f0f9 100644
--- a/src/core/ext/filters/deadline/deadline_filter.cc
+++ b/src/core/ext/filters/deadline/deadline_filter.cc
@@ -27,6 +27,7 @@
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/channel_init.h"
@@ -152,7 +153,11 @@ static void inject_recv_trailing_metadata_ready(
// Callback and associated state for starting the timer after call stack
// initialization has been completed.
struct start_timer_after_init_state {
- bool in_call_combiner;
+ start_timer_after_init_state(grpc_call_element* elem, grpc_millis deadline)
+ : elem(elem), deadline(deadline) {}
+ ~start_timer_after_init_state() { start_timer_if_needed(elem, deadline); }
+
+ bool in_call_combiner = false;
grpc_call_element* elem;
grpc_millis deadline;
grpc_closure closure;
@@ -171,20 +176,16 @@ static void start_timer_after_init(void* arg, grpc_error* error) {
"scheduling deadline timer");
return;
}
- start_timer_if_needed(state->elem, state->deadline);
- gpr_free(state);
+ grpc_core::Delete(state);
GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner,
"done scheduling deadline timer");
}
-void grpc_deadline_state_init(grpc_call_element* elem,
- grpc_call_stack* call_stack,
- grpc_call_combiner* call_combiner,
- grpc_millis deadline) {
- grpc_deadline_state* deadline_state =
- static_cast<grpc_deadline_state*>(elem->call_data);
- deadline_state->call_stack = call_stack;
- deadline_state->call_combiner = call_combiner;
+grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem,
+ grpc_call_stack* call_stack,
+ grpc_call_combiner* call_combiner,
+ grpc_millis deadline)
+ : call_stack(call_stack), call_combiner(call_combiner) {
// Deadline will always be infinite on servers, so the timer will only be
// set on clients with a finite deadline.
if (deadline != GRPC_MILLIS_INF_FUTURE) {
@@ -196,21 +197,14 @@ void grpc_deadline_state_init(grpc_call_element* elem,
// create a closure to start the timer, and we schedule that closure
// to be run after call stack initialization is done.
struct start_timer_after_init_state* state =
- static_cast<struct start_timer_after_init_state*>(
- gpr_zalloc(sizeof(*state)));
- state->elem = elem;
- state->deadline = deadline;
+ grpc_core::New<start_timer_after_init_state>(elem, deadline);
GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_SCHED(&state->closure, GRPC_ERROR_NONE);
}
}
-void grpc_deadline_state_destroy(grpc_call_element* elem) {
- grpc_deadline_state* deadline_state =
- static_cast<grpc_deadline_state*>(elem->call_data);
- cancel_timer_if_needed(deadline_state);
-}
+grpc_deadline_state::~grpc_deadline_state() { cancel_timer_if_needed(this); }
void grpc_deadline_state_reset(grpc_call_element* elem,
grpc_millis new_deadline) {
@@ -269,8 +263,8 @@ typedef struct server_call_data {
// Constructor for call_data. Used for both client and server filters.
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- grpc_deadline_state_init(elem, args->call_stack, args->call_combiner,
- args->deadline);
+ new (elem->call_data) grpc_deadline_state(
+ elem, args->call_stack, args->call_combiner, args->deadline);
return GRPC_ERROR_NONE;
}
@@ -278,7 +272,9 @@ static grpc_error* init_call_elem(grpc_call_element* elem,
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
- grpc_deadline_state_destroy(elem);
+ grpc_deadline_state* deadline_state =
+ static_cast<grpc_deadline_state*>(elem->call_data);
+ deadline_state->~grpc_deadline_state();
}
// Method for starting a call op for client filter.
diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h
index 1d797f445a..e37032999c 100644
--- a/src/core/ext/filters/deadline/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -22,19 +22,23 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/timer.h"
-typedef enum grpc_deadline_timer_state {
+enum grpc_deadline_timer_state {
GRPC_DEADLINE_STATE_INITIAL,
GRPC_DEADLINE_STATE_PENDING,
GRPC_DEADLINE_STATE_FINISHED
-} grpc_deadline_timer_state;
+};
// State used for filters that enforce call deadlines.
// Must be the first field in the filter's call_data.
-typedef struct grpc_deadline_state {
+struct grpc_deadline_state {
+ grpc_deadline_state(grpc_call_element* elem, grpc_call_stack* call_stack,
+ grpc_call_combiner* call_combiner, grpc_millis deadline);
+ ~grpc_deadline_state();
+
// We take a reference to the call stack for the timer callback.
grpc_call_stack* call_stack;
grpc_call_combiner* call_combiner;
- grpc_deadline_timer_state timer_state;
+ grpc_deadline_timer_state timer_state = GRPC_DEADLINE_STATE_INITIAL;
grpc_timer timer;
grpc_closure timer_callback;
// Closure to invoke when we receive trailing metadata.
@@ -43,21 +47,13 @@ typedef struct grpc_deadline_state {
// The original recv_trailing_metadata_ready closure, which we chain to
// after our own closure is invoked.
grpc_closure* original_recv_trailing_metadata_ready;
-} grpc_deadline_state;
+};
//
// NOTE: All of these functions require that the first field in
// elem->call_data is a grpc_deadline_state.
//
-// assumes elem->call_data is zero'd
-void grpc_deadline_state_init(grpc_call_element* elem,
- grpc_call_stack* call_stack,
- grpc_call_combiner* call_combiner,
- grpc_millis deadline);
-
-void grpc_deadline_state_destroy(grpc_call_element* elem);
-
// Cancels the existing timer and starts a new one with new_deadline.
//
// Note: It is generally safe to call this with an earlier deadline
diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc
index cd459e47cd..bf9a01f659 100644
--- a/src/core/ext/filters/http/client/http_client_filter.cc
+++ b/src/core/ext/filters/http/client/http_client_filter.cc
@@ -37,10 +37,31 @@
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
/* default maximum size of payload eligable for GET request */
-static const size_t kMaxPayloadSizeForGet = 2048;
+static constexpr size_t kMaxPayloadSizeForGet = 2048;
+
+static void recv_initial_metadata_ready(void* user_data, grpc_error* error);
+static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+static void on_send_message_next_done(void* arg, grpc_error* error);
+static void send_message_on_complete(void* arg, grpc_error* error);
namespace {
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call_combiner(args.call_combiner) {
+ GRPC_CLOSURE_INIT(&recv_initial_metadata_ready,
+ ::recv_initial_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ ::recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&on_send_message_next_done, ::on_send_message_next_done,
+ elem, grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&send_message_on_complete, ::send_message_on_complete,
+ elem, grpc_schedule_on_exec_ctx);
+ }
+
+ ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); }
+
grpc_call_combiner* call_combiner;
// State for handling send_initial_metadata ops.
grpc_linked_mdelem method;
@@ -51,18 +72,18 @@ struct call_data {
grpc_linked_mdelem user_agent;
// State for handling recv_initial_metadata ops.
grpc_metadata_batch* recv_initial_metadata;
- grpc_error* recv_initial_metadata_error;
- grpc_closure* original_recv_initial_metadata_ready;
+ grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+ grpc_closure* original_recv_initial_metadata_ready = nullptr;
grpc_closure recv_initial_metadata_ready;
// State for handling recv_trailing_metadata ops.
grpc_metadata_batch* recv_trailing_metadata;
grpc_closure* original_recv_trailing_metadata_ready;
grpc_closure recv_trailing_metadata_ready;
- grpc_error* recv_trailing_metadata_error;
- bool seen_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE;
+ bool seen_recv_trailing_metadata_ready = false;
// State for handling send_message ops.
grpc_transport_stream_op_batch* send_message_batch;
- size_t send_message_bytes_read;
+ size_t send_message_bytes_read = 0;
grpc_core::ManualConstructor<grpc_core::ByteStreamCache> send_message_cache;
grpc_core::ManualConstructor<grpc_core::ByteStreamCache::CachingByteStream>
send_message_caching_stream;
@@ -442,18 +463,7 @@ done:
/* Constructor for call_data */
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- calld->call_combiner = args->call_combiner;
- GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
- recv_initial_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
- recv_trailing_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete,
- elem, grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->on_send_message_next_done,
- on_send_message_next_done, elem, grpc_schedule_on_exec_ctx);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -462,7 +472,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- GRPC_ERROR_UNREF(calld->recv_initial_metadata_error);
+ calld->~call_data();
}
static grpc_mdelem scheme_from_args(const grpc_channel_args* args) {
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
index 933fe3c77b..9c8c8d9e18 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -39,6 +39,10 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/transport/static_metadata.h"
+static void start_send_message_batch(void* arg, grpc_error* unused);
+static void send_message_on_complete(void* arg, grpc_error* error);
+static void on_send_message_next_done(void* arg, grpc_error* error);
+
namespace {
enum initial_metadata_state {
// Initial metadata not yet seen.
@@ -50,6 +54,23 @@ enum initial_metadata_state {
};
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call_combiner(args.call_combiner) {
+ GRPC_CLOSURE_INIT(&start_send_message_batch_in_call_combiner,
+ start_send_message_batch, elem,
+ grpc_schedule_on_exec_ctx);
+ grpc_slice_buffer_init(&slices);
+ GRPC_CLOSURE_INIT(&send_message_on_complete, ::send_message_on_complete,
+ elem, grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&on_send_message_next_done, ::on_send_message_next_done,
+ elem, grpc_schedule_on_exec_ctx);
+ }
+
+ ~call_data() {
+ grpc_slice_buffer_destroy_internal(&slices);
+ GRPC_ERROR_UNREF(cancel_error);
+ }
+
grpc_call_combiner* call_combiner;
grpc_linked_mdelem compression_algorithm_storage;
grpc_linked_mdelem stream_compression_algorithm_storage;
@@ -57,11 +78,12 @@ struct call_data {
grpc_linked_mdelem accept_stream_encoding_storage;
/** Compression algorithm we'll try to use. It may be given by incoming
* metadata, or by the channel's default compression settings. */
- grpc_message_compression_algorithm message_compression_algorithm;
- initial_metadata_state send_initial_metadata_state;
- grpc_error* cancel_error;
+ grpc_message_compression_algorithm message_compression_algorithm =
+ GRPC_MESSAGE_COMPRESS_NONE;
+ initial_metadata_state send_initial_metadata_state = INITIAL_METADATA_UNSEEN;
+ grpc_error* cancel_error = GRPC_ERROR_NONE;
grpc_closure start_send_message_batch_in_call_combiner;
- grpc_transport_stream_op_batch* send_message_batch;
+ grpc_transport_stream_op_batch* send_message_batch = nullptr;
grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */
grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream>
replacement_stream;
@@ -424,16 +446,7 @@ static void compress_start_transport_stream_op_batch(
/* Constructor for call_data */
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- calld->call_combiner = args->call_combiner;
- calld->cancel_error = GRPC_ERROR_NONE;
- grpc_slice_buffer_init(&calld->slices);
- GRPC_CLOSURE_INIT(&calld->start_send_message_batch_in_call_combiner,
- start_send_message_batch, elem, grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->on_send_message_next_done,
- on_send_message_next_done, elem, grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete,
- elem, grpc_schedule_on_exec_ctx);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -442,8 +455,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- grpc_slice_buffer_destroy_internal(&calld->slices);
- GRPC_ERROR_UNREF(calld->cancel_error);
+ calld->~call_data();
}
/* Constructor for channel_data */
diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc
index 436ea09d94..ce1be8370c 100644
--- a/src/core/ext/filters/http/server/http_server_filter.cc
+++ b/src/core/ext/filters/http/server/http_server_filter.cc
@@ -35,9 +35,32 @@
#define EXPECTED_CONTENT_TYPE "application/grpc"
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
+static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err);
+static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err);
+static void hs_recv_message_ready(void* user_data, grpc_error* err);
+
namespace {
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call_combiner(args.call_combiner) {
+ GRPC_CLOSURE_INIT(&recv_initial_metadata_ready,
+ hs_recv_initial_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_message_ready, hs_recv_message_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ hs_recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ }
+
+ ~call_data() {
+ GRPC_ERROR_UNREF(recv_initial_metadata_ready_error);
+ if (have_read_stream) {
+ read_stream->Orphan();
+ }
+ }
+
grpc_call_combiner* call_combiner;
// Outgoing headers to add to send_initial_metadata.
@@ -47,27 +70,27 @@ struct call_data {
// If we see the recv_message contents in the GET query string, we
// store it here.
grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> read_stream;
- bool have_read_stream;
+ bool have_read_stream = false;
// State for intercepting recv_initial_metadata.
grpc_closure recv_initial_metadata_ready;
- grpc_error* recv_initial_metadata_ready_error;
+ grpc_error* recv_initial_metadata_ready_error = GRPC_ERROR_NONE;
grpc_closure* original_recv_initial_metadata_ready;
- grpc_metadata_batch* recv_initial_metadata;
+ grpc_metadata_batch* recv_initial_metadata = nullptr;
uint32_t* recv_initial_metadata_flags;
- bool seen_recv_initial_metadata_ready;
+ bool seen_recv_initial_metadata_ready = false;
// State for intercepting recv_message.
grpc_closure* original_recv_message_ready;
grpc_closure recv_message_ready;
grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
- bool seen_recv_message_ready;
+ bool seen_recv_message_ready = false;
// State for intercepting recv_trailing_metadata
grpc_closure recv_trailing_metadata_ready;
grpc_closure* original_recv_trailing_metadata_ready;
grpc_error* recv_trailing_metadata_ready_error;
- bool seen_recv_trailing_metadata_ready;
+ bool seen_recv_trailing_metadata_ready = false;
};
struct channel_data {
@@ -431,16 +454,7 @@ static void hs_start_transport_stream_op_batch(
/* Constructor for call_data */
static grpc_error* hs_init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- calld->call_combiner = args->call_combiner;
- GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
- hs_recv_initial_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_message_ready, hs_recv_message_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
- hs_recv_trailing_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -449,10 +463,7 @@ static void hs_destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- GRPC_ERROR_UNREF(calld->recv_initial_metadata_ready_error);
- if (calld->have_read_stream) {
- calld->read_stream->Orphan();
- }
+ calld->~call_data();
}
/* Constructor for channel_data */
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
index 8ac34c629f..6a7231ff7d 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
@@ -25,7 +25,6 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/ext/filters/load_reporting/registered_opencensus_objects.h"
#include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
#include "src/core/lib/channel/channel_args.h"
@@ -36,6 +35,7 @@
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/call.h"
+#include "src/core/lib/uri/uri_parser.h"
namespace grpc {
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 2d3b16d992..94d6942aa4 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -90,9 +90,53 @@ RefCountedPtr<MessageSizeLimits> MessageSizeLimits::CreateFromJson(
} // namespace
} // namespace grpc_core
+static void recv_message_ready(void* user_data, grpc_error* error);
+static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+
namespace {
+struct channel_data {
+ message_size_limits limits;
+ // Maps path names to refcounted_message_size_limits structs.
+ grpc_core::RefCountedPtr<grpc_core::SliceHashTable<
+ grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>>
+ method_limit_table;
+};
+
struct call_data {
+ call_data(grpc_call_element* elem, const channel_data& chand,
+ const grpc_call_element_args& args)
+ : call_combiner(args.call_combiner), limits(chand.limits) {
+ GRPC_CLOSURE_INIT(&recv_message_ready, ::recv_message_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ ::recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ // Get max sizes from channel data, then merge in per-method config values.
+ // Note: Per-method config is only available on the client, so we
+ // apply the max request size to the send limit and the max response
+ // size to the receive limit.
+ if (chand.method_limit_table != nullptr) {
+ grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits =
+ grpc_core::ServiceConfig::MethodConfigTableLookup(
+ *chand.method_limit_table, args.path);
+ if (limits != nullptr) {
+ if (limits->limits().max_send_size >= 0 &&
+ (limits->limits().max_send_size < this->limits.max_send_size ||
+ this->limits.max_send_size < 0)) {
+ this->limits.max_send_size = limits->limits().max_send_size;
+ }
+ if (limits->limits().max_recv_size >= 0 &&
+ (limits->limits().max_recv_size < this->limits.max_recv_size ||
+ this->limits.max_recv_size < 0)) {
+ this->limits.max_recv_size = limits->limits().max_recv_size;
+ }
+ }
+ }
+ }
+
+ ~call_data() { GRPC_ERROR_UNREF(error); }
+
grpc_call_combiner* call_combiner;
message_size_limits limits;
// Receive closures are chained: we inject this closure as the
@@ -101,25 +145,17 @@ struct call_data {
grpc_closure recv_message_ready;
grpc_closure recv_trailing_metadata_ready;
// The error caused by a message that is too large, or GRPC_ERROR_NONE
- grpc_error* error;
+ grpc_error* error = GRPC_ERROR_NONE;
// Used by recv_message_ready.
- grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
+ grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr;
// Original recv_message_ready callback, invoked after our own.
- grpc_closure* next_recv_message_ready;
+ grpc_closure* next_recv_message_ready = nullptr;
// Original recv_trailing_metadata callback, invoked after our own.
grpc_closure* original_recv_trailing_metadata_ready;
- bool seen_recv_trailing_metadata;
+ bool seen_recv_trailing_metadata = false;
grpc_error* recv_trailing_metadata_error;
};
-struct channel_data {
- message_size_limits limits;
- // Maps path names to refcounted_message_size_limits structs.
- grpc_core::RefCountedPtr<grpc_core::SliceHashTable<
- grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>>
- method_limit_table;
-};
-
} // namespace
// Callback invoked when we receive a message. Here we check the max
@@ -228,38 +264,7 @@ static void start_transport_stream_op_batch(
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- call_data* calld = static_cast<call_data*>(elem->call_data);
- calld->call_combiner = args->call_combiner;
- calld->next_recv_message_ready = nullptr;
- calld->original_recv_trailing_metadata_ready = nullptr;
- calld->error = GRPC_ERROR_NONE;
- GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
- recv_trailing_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- // Get max sizes from channel data, then merge in per-method config values.
- // Note: Per-method config is only available on the client, so we
- // apply the max request size to the send limit and the max response
- // size to the receive limit.
- calld->limits = chand->limits;
- if (chand->method_limit_table != nullptr) {
- grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits =
- grpc_core::ServiceConfig::MethodConfigTableLookup(
- *chand->method_limit_table, args->path);
- if (limits != nullptr) {
- if (limits->limits().max_send_size >= 0 &&
- (limits->limits().max_send_size < calld->limits.max_send_size ||
- calld->limits.max_send_size < 0)) {
- calld->limits.max_send_size = limits->limits().max_send_size;
- }
- if (limits->limits().max_recv_size >= 0 &&
- (limits->limits().max_recv_size < calld->limits.max_recv_size ||
- calld->limits.max_recv_size < 0)) {
- calld->limits.max_recv_size = limits->limits().max_recv_size;
- }
- }
- }
+ new (elem->call_data) call_data(elem, *chand, *args);
return GRPC_ERROR_NONE;
}
@@ -268,7 +273,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = (call_data*)elem->call_data;
- GRPC_ERROR_UNREF(calld->error);
+ calld->~call_data();
}
static int default_size(const grpc_channel_args* args,
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
index 60a32022f5..42a2e2e896 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
@@ -117,8 +117,9 @@ static void on_handshake_done(void* arg, grpc_error* error) {
c->args.interested_parties);
c->result->transport =
grpc_create_chttp2_transport(args->args, args->endpoint, true);
- c->result->socket_uuid =
- grpc_chttp2_transport_get_socket_uuid(c->result->transport);
+ grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> socket_node =
+ grpc_chttp2_transport_get_socket_node(c->result->transport);
+ c->result->socket_uuid = socket_node == nullptr ? 0 : socket_node->uuid();
GPR_ASSERT(c->result->transport);
// TODO(roth): We ideally want to wait until we receive HTTP/2
// settings from the server before we consider the connection
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
index 5ce73a95d7..e73eee4353 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
@@ -27,7 +27,6 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/memory.h"
@@ -39,6 +38,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/uri/uri_parser.h"
static void client_channel_factory_ref(
grpc_client_channel_factory* cc_factory) {}
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc
index 07b304b320..3d09187b9b 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.cc
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc
@@ -37,8 +37,10 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/handshaker_registry.h"
+#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
@@ -114,9 +116,16 @@ static void on_handshake_done(void* arg, grpc_error* error) {
server_connection_state* connection_state =
static_cast<server_connection_state*>(args->user_data);
gpr_mu_lock(&connection_state->svr_state->mu);
+ grpc_resource_user* resource_user = grpc_server_get_default_resource_user(
+ connection_state->svr_state->server);
if (error != GRPC_ERROR_NONE || connection_state->svr_state->shutdown) {
const char* error_str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
+ grpc_resource_user* resource_user = grpc_server_get_default_resource_user(
+ connection_state->svr_state->server);
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
if (error == GRPC_ERROR_NONE && args->endpoint != nullptr) {
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
@@ -135,12 +144,12 @@ static void on_handshake_done(void* arg, grpc_error* error) {
// handshaker may have handed off the connection to some external
// code, so we can just clean up here without creating a transport.
if (args->endpoint != nullptr) {
- grpc_transport* transport =
- grpc_create_chttp2_transport(args->args, args->endpoint, false);
+ grpc_transport* transport = grpc_create_chttp2_transport(
+ args->args, args->endpoint, false, resource_user);
grpc_server_setup_transport(
connection_state->svr_state->server, transport,
connection_state->accepting_pollset, args->args,
- grpc_chttp2_transport_get_socket_uuid(transport));
+ grpc_chttp2_transport_get_socket_node(transport), resource_user);
// Use notify_on_receive_settings callback to enforce the
// handshake deadline.
connection_state->transport =
@@ -159,6 +168,11 @@ static void on_handshake_done(void* arg, grpc_error* error) {
connection_state, grpc_schedule_on_exec_ctx);
grpc_timer_init(&connection_state->timer, connection_state->deadline,
&connection_state->on_timeout);
+ } else {
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
}
}
grpc_handshake_manager_pending_list_remove(
@@ -183,6 +197,20 @@ static void on_accept(void* arg, grpc_endpoint* tcp,
gpr_free(acceptor);
return;
}
+ grpc_resource_user* resource_user =
+ grpc_server_get_default_resource_user(state->server);
+ if (resource_user != nullptr &&
+ !grpc_resource_user_safe_alloc(resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE)) {
+ gpr_log(
+ GPR_ERROR,
+ "Memory quota exhausted, rejecting the connection, no handshaking.");
+ gpr_mu_unlock(&state->mu);
+ grpc_endpoint_shutdown(tcp, GRPC_ERROR_NONE);
+ grpc_endpoint_destroy(tcp);
+ gpr_free(acceptor);
+ return;
+ }
grpc_handshake_manager* handshake_mgr = grpc_handshake_manager_create();
grpc_handshake_manager_pending_list_add(&state->pending_handshake_mgrs,
handshake_mgr);
@@ -338,9 +366,10 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr,
grpc_resolved_addresses_destroy(resolved);
arg = grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ);
- if (grpc_channel_arg_get_bool(arg, false)) {
+ if (grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT)) {
state->channelz_listen_socket =
- grpc_core::MakeRefCounted<grpc_core::channelz::ListenSocketNode>();
+ grpc_core::MakeRefCounted<grpc_core::channelz::ListenSocketNode>(
+ grpc_core::UniquePtr<char>(gpr_strdup(addr)));
socket_uuid = state->channelz_listen_socket->uuid();
}
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
index b9024a87e2..c29c1e58cd 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -61,7 +61,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
grpc_endpoint_add_to_pollset(server_endpoint, pollsets[i]);
}
- grpc_server_setup_transport(server, transport, nullptr, server_args, 0);
+ grpc_server_setup_transport(server, transport, nullptr, server_args, nullptr);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 8a481bb7d5..9b6574b612 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/transport/chttp2/transport/context_list.h"
#include "src/core/ext/transport/chttp2/transport/frame_data.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
@@ -53,6 +54,7 @@
#include "src/core/lib/transport/timeout_encoding.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/lib/transport/transport_impl.h"
+#include "src/core/lib/uri/uri_parser.h"
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
@@ -154,84 +156,57 @@ bool g_flow_control_enabled = true;
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
-static void destruct_transport(grpc_chttp2_transport* t) {
+grpc_chttp2_transport::~grpc_chttp2_transport() {
size_t i;
- if (t->channelz_socket != nullptr) {
- t->channelz_socket.reset();
+ if (channelz_socket != nullptr) {
+ channelz_socket.reset();
}
- grpc_endpoint_destroy(t->ep);
+ grpc_endpoint_destroy(ep);
+
+ grpc_slice_buffer_destroy_internal(&qbuf);
- grpc_slice_buffer_destroy_internal(&t->qbuf);
+ grpc_slice_buffer_destroy_internal(&outbuf);
+ grpc_chttp2_hpack_compressor_destroy(&hpack_compressor);
- grpc_slice_buffer_destroy_internal(&t->outbuf);
- grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
+ grpc_core::ContextList::Execute(cl, nullptr, GRPC_ERROR_NONE);
+ cl = nullptr;
- grpc_slice_buffer_destroy_internal(&t->read_buffer);
- grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
- grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
+ grpc_slice_buffer_destroy_internal(&read_buffer);
+ grpc_chttp2_hpack_parser_destroy(&hpack_parser);
+ grpc_chttp2_goaway_parser_destroy(&goaway_parser);
for (i = 0; i < STREAM_LIST_COUNT; i++) {
- GPR_ASSERT(t->lists[i].head == nullptr);
- GPR_ASSERT(t->lists[i].tail == nullptr);
+ GPR_ASSERT(lists[i].head == nullptr);
+ GPR_ASSERT(lists[i].tail == nullptr);
}
- GRPC_ERROR_UNREF(t->goaway_error);
+ GRPC_ERROR_UNREF(goaway_error);
- GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0);
+ GPR_ASSERT(grpc_chttp2_stream_map_size(&stream_map) == 0);
- grpc_chttp2_stream_map_destroy(&t->stream_map);
- grpc_connectivity_state_destroy(&t->channel_callback.state_tracker);
+ grpc_chttp2_stream_map_destroy(&stream_map);
+ grpc_connectivity_state_destroy(&channel_callback.state_tracker);
- GRPC_COMBINER_UNREF(t->combiner, "chttp2_transport");
+ GRPC_COMBINER_UNREF(combiner, "chttp2_transport");
- cancel_pings(t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"));
+ cancel_pings(this,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"));
- while (t->write_cb_pool) {
- grpc_chttp2_write_cb* next = t->write_cb_pool->next;
- gpr_free(t->write_cb_pool);
- t->write_cb_pool = next;
+ while (write_cb_pool) {
+ grpc_chttp2_write_cb* next = write_cb_pool->next;
+ gpr_free(write_cb_pool);
+ write_cb_pool = next;
}
- t->flow_control.Destroy();
+ flow_control.Destroy();
- GRPC_ERROR_UNREF(t->closed_with_error);
- gpr_free(t->ping_acks);
- gpr_free(t->peer_string);
- gpr_free(t);
-}
-
-#ifndef NDEBUG
-void grpc_chttp2_unref_transport(grpc_chttp2_transport* t, const char* reason,
- const char* file, int line) {
- if (grpc_trace_chttp2_refcount.enabled()) {
- gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count);
- gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]",
- t, val, val - 1, reason, file, line);
- }
- if (!gpr_unref(&t->refs)) return;
- destruct_transport(t);
+ GRPC_ERROR_UNREF(closed_with_error);
+ gpr_free(ping_acks);
+ gpr_free(peer_string);
}
-void grpc_chttp2_ref_transport(grpc_chttp2_transport* t, const char* reason,
- const char* file, int line) {
- if (grpc_trace_chttp2_refcount.enabled()) {
- gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count);
- gpr_log(GPR_DEBUG, "chttp2: ref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]",
- t, val, val + 1, reason, file, line);
- }
- gpr_ref(&t->refs);
-}
-#else
-void grpc_chttp2_unref_transport(grpc_chttp2_transport* t) {
- if (!gpr_unref(&t->refs)) return;
- destruct_transport(t);
-}
-
-void grpc_chttp2_ref_transport(grpc_chttp2_transport* t) { gpr_ref(&t->refs); }
-#endif
-
static const grpc_transport_vtable* get_vtable(void);
/* Returns whether bdp is enabled */
@@ -395,8 +370,12 @@ static bool read_channel_args(grpc_chttp2_transport* t,
}
}
if (channelz_enabled) {
+ // TODO(ncteisen): add an API to endpoint to query for local addr, and pass
+ // it in here, so SocketNode knows its own address.
t->channelz_socket =
- grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>();
+ grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>(
+ grpc_core::UniquePtr<char>(),
+ grpc_core::UniquePtr<char>(gpr_strdup(t->peer_string)));
}
return enable_bdp;
}
@@ -476,113 +455,96 @@ static void init_keepalive_pings_if_enabled(grpc_chttp2_transport* t) {
}
}
-static void init_transport(grpc_chttp2_transport* t,
- const grpc_channel_args* channel_args,
- grpc_endpoint* ep, bool is_client) {
+grpc_chttp2_transport::grpc_chttp2_transport(
+ const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* resource_user)
+ : refs(1, &grpc_trace_chttp2_refcount),
+ ep(ep),
+ peer_string(grpc_endpoint_get_peer(ep)),
+ resource_user(resource_user),
+ combiner(grpc_combiner_create()),
+ is_client(is_client),
+ next_stream_id(is_client ? 1 : 2),
+ deframe_state(is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0) {
GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
-
- t->base.vtable = get_vtable();
- t->ep = ep;
- /* one ref is for destroy */
- gpr_ref_init(&t->refs, 1);
- t->combiner = grpc_combiner_create();
- t->peer_string = grpc_endpoint_get_peer(ep);
- t->endpoint_reading = 1;
- t->next_stream_id = is_client ? 1 : 2;
- t->is_client = is_client;
- t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
- t->is_first_frame = true;
- grpc_connectivity_state_init(
- &t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
- is_client ? "client_transport" : "server_transport");
-
- grpc_slice_buffer_init(&t->qbuf);
- grpc_slice_buffer_init(&t->outbuf);
- grpc_chttp2_hpack_compressor_init(&t->hpack_compressor);
-
- init_transport_closures(t);
-
- t->goaway_error = GRPC_ERROR_NONE;
- grpc_chttp2_goaway_parser_init(&t->goaway_parser);
- grpc_chttp2_hpack_parser_init(&t->hpack_parser);
-
- grpc_slice_buffer_init(&t->read_buffer);
-
+ base.vtable = get_vtable();
/* 8 is a random stab in the dark as to a good initial size: it's small enough
that it shouldn't waste memory for infrequently used connections, yet
large enough that the exponential growth should happen nicely when it's
needed.
TODO(ctiller): tune this */
- grpc_chttp2_stream_map_init(&t->stream_map, 8);
+ grpc_chttp2_stream_map_init(&stream_map, 8);
+ grpc_slice_buffer_init(&read_buffer);
+ grpc_connectivity_state_init(
+ &channel_callback.state_tracker, GRPC_CHANNEL_READY,
+ is_client ? "client_transport" : "server_transport");
+ grpc_slice_buffer_init(&outbuf);
+ if (is_client) {
+ grpc_slice_buffer_add(&outbuf, grpc_slice_from_copied_string(
+ GRPC_CHTTP2_CLIENT_CONNECT_STRING));
+ }
+ grpc_chttp2_hpack_compressor_init(&hpack_compressor);
+ grpc_slice_buffer_init(&qbuf);
/* copy in initial settings to all setting sets */
size_t i;
int j;
for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
- t->settings[j][i] = grpc_chttp2_settings_parameters[i].default_value;
+ settings[j][i] = grpc_chttp2_settings_parameters[i].default_value;
}
}
- t->dirtied_local_settings = 1;
- /* Hack: it's common for implementations to assume 65536 bytes initial send
- window -- this should by rights be 0 */
- t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
- t->sent_local_settings = 0;
- t->write_buffer_size = grpc_core::chttp2::kDefaultWindow;
+ grpc_chttp2_hpack_parser_init(&hpack_parser);
+ grpc_chttp2_goaway_parser_init(&goaway_parser);
- if (is_client) {
- grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
- GRPC_CHTTP2_CLIENT_CONNECT_STRING));
- }
+ init_transport_closures(this);
/* configure http2 the way we like it */
if (is_client) {
- queue_setting_update(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
- queue_setting_update(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
}
- queue_setting_update(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
DEFAULT_MAX_HEADER_LIST_SIZE);
- queue_setting_update(t, GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA,
- 1);
+ queue_setting_update(this,
+ GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1);
- configure_transport_ping_policy(t);
- init_transport_keepalive_settings(t);
-
- t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
+ configure_transport_ping_policy(this);
+ init_transport_keepalive_settings(this);
bool enable_bdp = true;
if (channel_args) {
- enable_bdp = read_channel_args(t, channel_args, is_client);
+ enable_bdp = read_channel_args(this, channel_args, is_client);
}
if (g_flow_control_enabled) {
- t->flow_control.Init<grpc_core::chttp2::TransportFlowControl>(t,
- enable_bdp);
+ flow_control.Init<grpc_core::chttp2::TransportFlowControl>(this,
+ enable_bdp);
} else {
- t->flow_control.Init<grpc_core::chttp2::TransportFlowControlDisabled>(t);
+ flow_control.Init<grpc_core::chttp2::TransportFlowControlDisabled>(this);
enable_bdp = false;
}
/* No pings allowed before receiving a header or data frame. */
- t->ping_state.pings_before_data_required = 0;
- t->ping_state.is_delayed_ping_timer_set = false;
- t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
+ ping_state.pings_before_data_required = 0;
+ ping_state.is_delayed_ping_timer_set = false;
+ ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
- t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
- t->ping_recv_state.ping_strikes = 0;
+ ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
+ ping_recv_state.ping_strikes = 0;
- init_keepalive_pings_if_enabled(t);
+ init_keepalive_pings_if_enabled(this);
if (enable_bdp) {
- GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
- schedule_bdp_ping_locked(t);
- grpc_chttp2_act_on_flowctl_action(t->flow_control->PeriodicUpdate(), t,
+ GRPC_CHTTP2_REF_TRANSPORT(this, "bdp_ping");
+ schedule_bdp_ping_locked(this);
+ grpc_chttp2_act_on_flowctl_action(flow_control->PeriodicUpdate(), this,
nullptr);
}
- grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE);
- post_benign_reclaimer(t);
+ grpc_chttp2_initiate_write(this, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE);
+ post_benign_reclaimer(this);
}
static void destroy_transport_locked(void* tp, grpc_error* error) {
@@ -592,6 +554,7 @@ static void destroy_transport_locked(void* tp, grpc_error* error) {
t, grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state));
+ // Must be the last line.
GRPC_CHTTP2_UNREF_TRANSPORT(t, "destroy");
}
@@ -676,111 +639,108 @@ void grpc_chttp2_stream_unref(grpc_chttp2_stream* s) {
}
#endif
-static int init_stream(grpc_transport* gt, grpc_stream* gs,
- grpc_stream_refcount* refcount, const void* server_data,
- gpr_arena* arena) {
- GPR_TIMER_SCOPE("init_stream", 0);
- grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
- grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs);
-
- s->t = t;
- s->refcount = refcount;
+grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t,
+ grpc_stream_refcount* refcount,
+ const void* server_data,
+ gpr_arena* arena)
+ : t(t), refcount(refcount), metadata_buffer{{arena}, {arena}} {
/* We reserve one 'active stream' that's dropped when the stream is
read-closed. The others are for Chttp2IncomingByteStreams that are
actively reading */
- GRPC_CHTTP2_STREAM_REF(s, "chttp2");
-
- grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena);
- grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena);
- grpc_chttp2_data_parser_init(&s->data_parser);
- grpc_slice_buffer_init(&s->flow_controlled_buffer);
- s->deadline = GRPC_MILLIS_INF_FUTURE;
- GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s,
- grpc_schedule_on_exec_ctx);
- grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer);
- s->unprocessed_incoming_frames_buffer_cached_length = 0;
- grpc_slice_buffer_init(&s->frame_storage);
- grpc_slice_buffer_init(&s->compressed_data_buffer);
- grpc_slice_buffer_init(&s->decompressed_data_buffer);
- s->pending_byte_stream = false;
- s->decompressed_header_bytes = 0;
- GRPC_CLOSURE_INIT(&s->reset_byte_stream, reset_byte_stream, s,
- grpc_combiner_scheduler(t->combiner));
-
+ GRPC_CHTTP2_STREAM_REF(this, "chttp2");
GRPC_CHTTP2_REF_TRANSPORT(t, "stream");
if (server_data) {
- s->id = static_cast<uint32_t>((uintptr_t)server_data);
- *t->accepting_stream = s;
- grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+ id = static_cast<uint32_t>((uintptr_t)server_data);
+ *t->accepting_stream = this;
+ grpc_chttp2_stream_map_add(&t->stream_map, id, this);
post_destructive_reclaimer(t);
}
-
if (t->flow_control->flow_control_enabled()) {
- s->flow_control.Init<grpc_core::chttp2::StreamFlowControl>(
+ flow_control.Init<grpc_core::chttp2::StreamFlowControl>(
static_cast<grpc_core::chttp2::TransportFlowControl*>(
t->flow_control.get()),
- s);
+ this);
} else {
- s->flow_control.Init<grpc_core::chttp2::StreamFlowControlDisabled>();
+ flow_control.Init<grpc_core::chttp2::StreamFlowControlDisabled>();
}
- return 0;
-}
+ grpc_slice_buffer_init(&frame_storage);
+ grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer);
+ grpc_slice_buffer_init(&flow_controlled_buffer);
+ grpc_slice_buffer_init(&compressed_data_buffer);
+ grpc_slice_buffer_init(&decompressed_data_buffer);
-static void destroy_stream_locked(void* sp, grpc_error* error) {
- GPR_TIMER_SCOPE("destroy_stream", 0);
- grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
- grpc_chttp2_transport* t = s->t;
+ GRPC_CLOSURE_INIT(&complete_fetch_locked, ::complete_fetch_locked, this,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&reset_byte_stream, ::reset_byte_stream, this,
+ grpc_combiner_scheduler(t->combiner));
+}
+grpc_chttp2_stream::~grpc_chttp2_stream() {
if (t->channelz_socket != nullptr) {
- if ((t->is_client && s->eos_received) || (!t->is_client && s->eos_sent)) {
+ if ((t->is_client && eos_received) || (!t->is_client && eos_sent)) {
t->channelz_socket->RecordStreamSucceeded();
} else {
t->channelz_socket->RecordStreamFailed();
}
}
- GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0);
- if (s->id != 0) {
- GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == nullptr);
+ GPR_ASSERT((write_closed && read_closed) || id == 0);
+ if (id != 0) {
+ GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, id) == nullptr);
}
- grpc_slice_buffer_destroy_internal(&s->unprocessed_incoming_frames_buffer);
- grpc_slice_buffer_destroy_internal(&s->frame_storage);
- grpc_slice_buffer_destroy_internal(&s->compressed_data_buffer);
- grpc_slice_buffer_destroy_internal(&s->decompressed_data_buffer);
+ grpc_slice_buffer_destroy_internal(&unprocessed_incoming_frames_buffer);
+ grpc_slice_buffer_destroy_internal(&frame_storage);
+ grpc_slice_buffer_destroy_internal(&compressed_data_buffer);
+ grpc_slice_buffer_destroy_internal(&decompressed_data_buffer);
- grpc_chttp2_list_remove_stalled_by_transport(t, s);
- grpc_chttp2_list_remove_stalled_by_stream(t, s);
+ grpc_chttp2_list_remove_stalled_by_transport(t, this);
+ grpc_chttp2_list_remove_stalled_by_stream(t, this);
for (int i = 0; i < STREAM_LIST_COUNT; i++) {
- if (GPR_UNLIKELY(s->included[i])) {
+ if (GPR_UNLIKELY(included[i])) {
gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
- t->is_client ? "client" : "server", s->id, i);
+ t->is_client ? "client" : "server", id, i);
abort();
}
}
- GPR_ASSERT(s->send_initial_metadata_finished == nullptr);
- GPR_ASSERT(s->fetching_send_message == nullptr);
- GPR_ASSERT(s->send_trailing_metadata_finished == nullptr);
- GPR_ASSERT(s->recv_initial_metadata_ready == nullptr);
- GPR_ASSERT(s->recv_message_ready == nullptr);
- GPR_ASSERT(s->recv_trailing_metadata_finished == nullptr);
- grpc_chttp2_data_parser_destroy(&s->data_parser);
- grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]);
- grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]);
- grpc_slice_buffer_destroy_internal(&s->flow_controlled_buffer);
- GRPC_ERROR_UNREF(s->read_closed_error);
- GRPC_ERROR_UNREF(s->write_closed_error);
- GRPC_ERROR_UNREF(s->byte_stream_error);
+ GPR_ASSERT(send_initial_metadata_finished == nullptr);
+ GPR_ASSERT(fetching_send_message == nullptr);
+ GPR_ASSERT(send_trailing_metadata_finished == nullptr);
+ GPR_ASSERT(recv_initial_metadata_ready == nullptr);
+ GPR_ASSERT(recv_message_ready == nullptr);
+ GPR_ASSERT(recv_trailing_metadata_finished == nullptr);
+ grpc_slice_buffer_destroy_internal(&flow_controlled_buffer);
+ GRPC_ERROR_UNREF(read_closed_error);
+ GRPC_ERROR_UNREF(write_closed_error);
+ GRPC_ERROR_UNREF(byte_stream_error);
- s->flow_control.Destroy();
+ flow_control.Destroy();
+
+ if (t->resource_user != nullptr) {
+ grpc_resource_user_free(t->resource_user, GRPC_RESOURCE_QUOTA_CALL_SIZE);
+ }
GRPC_CHTTP2_UNREF_TRANSPORT(t, "stream");
+ GRPC_CLOSURE_SCHED(destroy_stream_arg, GRPC_ERROR_NONE);
+}
+
+static int init_stream(grpc_transport* gt, grpc_stream* gs,
+ grpc_stream_refcount* refcount, const void* server_data,
+ gpr_arena* arena) {
+ GPR_TIMER_SCOPE("init_stream", 0);
+ grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
+ new (gs) grpc_chttp2_stream(t, refcount, server_data, arena);
+ return 0;
+}
- GRPC_CLOSURE_SCHED(s->destroy_stream_arg, GRPC_ERROR_NONE);
+static void destroy_stream_locked(void* sp, grpc_error* error) {
+ GPR_TIMER_SCOPE("destroy_stream", 0);
+ grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
+ s->~grpc_chttp2_stream();
}
static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
@@ -816,7 +776,21 @@ grpc_chttp2_stream* grpc_chttp2_parsing_accept_stream(grpc_chttp2_transport* t,
if (t->channel_callback.accept_stream == nullptr) {
return nullptr;
}
- grpc_chttp2_stream* accepting;
+ // Don't accept the stream if memory quota doesn't allow. Note that we should
+ // simply refuse the stream here instead of canceling the stream after it's
+ // accepted since the latter will create the call which costs much memory.
+ if (t->resource_user != nullptr &&
+ !grpc_resource_user_safe_alloc(t->resource_user,
+ GRPC_RESOURCE_QUOTA_CALL_SIZE)) {
+ gpr_log(GPR_ERROR, "Memory exhausted, rejecting the stream.");
+ grpc_slice_buffer_add(
+ &t->qbuf,
+ grpc_chttp2_rst_stream_create(
+ id, static_cast<uint32_t>(GRPC_HTTP2_REFUSED_STREAM), nullptr));
+ grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RST_STREAM);
+ return nullptr;
+ }
+ grpc_chttp2_stream* accepting = nullptr;
GPR_ASSERT(t->accepting_stream == nullptr);
t->accepting_stream = &accepting;
t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
@@ -1063,11 +1037,13 @@ static void write_action_begin_locked(void* gt, grpc_error* error_ignored) {
static void write_action(void* gt, grpc_error* error) {
GPR_TIMER_SCOPE("write_action", 0);
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
+ void* cl = t->cl;
+ t->cl = nullptr;
grpc_endpoint_write(
t->ep, &t->outbuf,
GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end_locked, t,
grpc_combiner_scheduler(t->combiner)),
- nullptr);
+ cl);
}
/* Callback from the grpc_endpoint after bytes have been written by calling
@@ -1391,6 +1367,8 @@ static void perform_stream_op_locked(void* stream_op,
GRPC_STATS_INC_HTTP2_OP_BATCHES();
+ s->context = op->payload->context;
+ s->traced = op->is_traced;
if (grpc_http_trace.enabled()) {
char* str = grpc_transport_stream_op_batch_string(op);
gpr_log(GPR_INFO, "perform_stream_op_locked: %s; on_complete = %p", str,
@@ -1701,8 +1679,8 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
gpr_free(str);
}
- op->handler_private.extra_arg = gs;
GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op");
+ op->handler_private.extra_arg = gs;
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&op->handler_private.closure, perform_stream_op_locked,
op, grpc_combiner_scheduler(t->combiner)),
@@ -2708,6 +2686,7 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end");
+ grpc_timer_init_unset(&t->keepalive_watchdog_timer);
send_keepalive_ping_locked(t);
grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING);
} else {
@@ -2834,8 +2813,8 @@ Chttp2IncomingByteStream::Chttp2IncomingByteStream(
: ByteStream(frame_size, flags),
transport_(transport),
stream_(stream),
+ refs_(2),
remaining_bytes_(frame_size) {
- gpr_ref_init(&refs_, 2);
GRPC_ERROR_UNREF(stream->byte_stream_error);
stream->byte_stream_error = GRPC_ERROR_NONE;
}
@@ -2860,14 +2839,6 @@ void Chttp2IncomingByteStream::Orphan() {
GRPC_ERROR_NONE);
}
-void Chttp2IncomingByteStream::Unref() {
- if (gpr_unref(&refs_)) {
- Delete(this);
- }
-}
-
-void Chttp2IncomingByteStream::Ref() { gpr_ref(&refs_); }
-
void Chttp2IncomingByteStream::NextLocked(void* arg,
grpc_error* error_ignored) {
Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
@@ -3174,21 +3145,18 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
static const grpc_transport_vtable* get_vtable(void) { return &vtable; }
-intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport) {
+grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode>
+grpc_chttp2_transport_get_socket_node(grpc_transport* transport) {
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(transport);
- if (t->channelz_socket != nullptr) {
- return t->channelz_socket->uuid();
- } else {
- return 0;
- }
+ return t->channelz_socket;
}
grpc_transport* grpc_create_chttp2_transport(
- const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client) {
- grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(
- gpr_zalloc(sizeof(grpc_chttp2_transport)));
- init_transport(t, channel_args, ep, is_client);
+ const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* resource_user) {
+ auto t = grpc_core::New<grpc_chttp2_transport>(channel_args, ep, is_client,
+ resource_user);
return &t->base;
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index e5872fee43..c22cfb0ad7 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/transport/transport.h"
@@ -32,9 +33,11 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount;
extern bool g_flow_control_enabled;
grpc_transport* grpc_create_chttp2_transport(
- const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client);
+ const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* resource_user = nullptr);
-intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport);
+grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode>
+grpc_chttp2_transport_get_socket_node(grpc_transport* transport);
/// Takes ownership of \a read_buffer, which (if non-NULL) contains
/// leftover bytes previously read from the endpoint (e.g., by handshakers).
diff --git a/src/core/ext/transport/chttp2/transport/context_list.cc b/src/core/ext/transport/chttp2/transport/context_list.cc
new file mode 100644
index 0000000000..f30d41c332
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/context_list.cc
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/transport/chttp2/transport/context_list.h"
+
+namespace {
+void (*write_timestamps_callback_g)(void*, grpc_core::Timestamps*) = nullptr;
+}
+
+namespace grpc_core {
+void ContextList::Execute(void* arg, grpc_core::Timestamps* ts,
+ grpc_error* error) {
+ ContextList* head = static_cast<ContextList*>(arg);
+ ContextList* to_be_freed;
+ while (head != nullptr) {
+ if (error == GRPC_ERROR_NONE && ts != nullptr) {
+ if (write_timestamps_callback_g) {
+ ts->byte_offset = static_cast<uint32_t>(head->byte_offset_);
+ write_timestamps_callback_g(head->s_->context, ts);
+ }
+ }
+ GRPC_CHTTP2_STREAM_UNREF(static_cast<grpc_chttp2_stream*>(head->s_),
+ "timestamp");
+ to_be_freed = head;
+ head = head->next_;
+ grpc_core::Delete(to_be_freed);
+ }
+}
+
+void grpc_http2_set_write_timestamps_callback(
+ void (*fn)(void*, grpc_core::Timestamps*)) {
+ write_timestamps_callback_g = fn;
+}
+} /* namespace grpc_core */
diff --git a/src/core/ext/transport/chttp2/transport/context_list.h b/src/core/ext/transport/chttp2/transport/context_list.h
new file mode 100644
index 0000000000..d870107749
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/context_list.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/buffer_list.h"
+
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+namespace grpc_core {
+/** A list of RPC Contexts */
+class ContextList {
+ public:
+ /* Creates a new element with \a context as the value and appends it to the
+ * list. */
+ static void Append(ContextList** head, grpc_chttp2_stream* s) {
+ /* Make sure context is not already present */
+ GRPC_CHTTP2_STREAM_REF(s, "timestamp");
+
+#ifndef NDEBUG
+ ContextList* ptr = *head;
+ while (ptr != nullptr) {
+ if (ptr->s_ == s) {
+ GPR_ASSERT(
+ false &&
+ "Trying to append a stream that is already present in the list");
+ }
+ ptr = ptr->next_;
+ }
+#endif
+
+ /* Create a new element in the list and add it at the front */
+ ContextList* elem = grpc_core::New<ContextList>();
+ elem->s_ = s;
+ elem->byte_offset_ = s->byte_counter;
+ elem->next_ = *head;
+ *head = elem;
+ }
+
+ /* Executes a function \a fn with each context in the list and \a ts. It also
+ * frees up the entire list after this operation. */
+ static void Execute(void* arg, grpc_core::Timestamps* ts, grpc_error* error);
+
+ private:
+ grpc_chttp2_stream* s_ = nullptr;
+ ContextList* next_ = nullptr;
+ size_t byte_offset_ = 0;
+};
+
+void grpc_http2_set_write_timestamps_callback(
+ void (*fn)(void*, grpc_core::Timestamps*));
+} /* namespace grpc_core */
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc
index 933b32c03c..1de00735cf 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_data.cc
@@ -32,18 +32,12 @@
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/transport.h"
-grpc_error* grpc_chttp2_data_parser_init(grpc_chttp2_data_parser* parser) {
- parser->state = GRPC_CHTTP2_DATA_FH_0;
- parser->parsing_frame = nullptr;
- return GRPC_ERROR_NONE;
-}
-
-void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser* parser) {
- if (parser->parsing_frame != nullptr) {
- GRPC_ERROR_UNREF(parser->parsing_frame->Finished(
+grpc_chttp2_data_parser::~grpc_chttp2_data_parser() {
+ if (parsing_frame != nullptr) {
+ GRPC_ERROR_UNREF(parsing_frame->Finished(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false));
}
- GRPC_ERROR_UNREF(parser->error);
+ GRPC_ERROR_UNREF(error);
}
grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser,
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index e5d01f764e..2c5da99fa6 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -43,20 +43,18 @@ namespace grpc_core {
class Chttp2IncomingByteStream;
} // namespace grpc_core
-typedef struct {
- grpc_chttp2_stream_state state;
- uint8_t frame_type;
- uint32_t frame_size;
- grpc_error* error;
+struct grpc_chttp2_data_parser {
+ grpc_chttp2_data_parser() = default;
+ ~grpc_chttp2_data_parser();
- bool is_frame_compressed;
- grpc_core::Chttp2IncomingByteStream* parsing_frame;
-} grpc_chttp2_data_parser;
+ grpc_chttp2_stream_state state = GRPC_CHTTP2_DATA_FH_0;
+ uint8_t frame_type = 0;
+ uint32_t frame_size = 0;
+ grpc_error* error = GRPC_ERROR_NONE;
-/* initialize per-stream state for data frame parsing */
-grpc_error* grpc_chttp2_data_parser_init(grpc_chttp2_data_parser* parser);
-
-void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser* parser);
+ bool is_frame_compressed = false;
+ grpc_core::Chttp2IncomingByteStream* parsing_frame = nullptr;
+};
/* start processing a new data frame */
grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser,
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
index 4bdd4309a4..a0a7534594 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
@@ -32,7 +32,7 @@ grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
grpc_transport_one_way_stats* stats) {
static const size_t frame_size = 13;
grpc_slice slice = GRPC_SLICE_MALLOC(frame_size);
- stats->framing_bytes += frame_size;
+ if (stats != nullptr) stats->framing_bytes += frame_size;
uint8_t* p = GRPC_SLICE_START_PTR(slice);
// Frame size.
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 920d52770f..dbe9df6ae3 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -212,10 +212,6 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
return new_index;
}
-/* dummy function */
-static void add_nothing(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
- size_t elem_size) {}
-
// Add a key to the dynamic table. Both key and value will be added to table at
// the decoder.
static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
@@ -524,17 +520,22 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
uint32_t indices_key;
/* should this elem be in the table? */
- size_t decoder_space_usage =
+ const size_t decoder_space_usage =
grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
- bool should_add_elem = elem_interned &&
- decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
- c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
- c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
- void (*maybe_add)(grpc_chttp2_hpack_compressor*, grpc_mdelem, size_t) =
- should_add_elem ? add_elem : add_nothing;
- void (*emit)(grpc_chttp2_hpack_compressor*, uint32_t, grpc_mdelem,
- framer_state*) =
- should_add_elem ? emit_lithdr_incidx : emit_lithdr_noidx;
+ const bool should_add_elem = elem_interned &&
+ decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
+ c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
+ c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
+
+ auto emit_maybe_add = [&should_add_elem, &elem, &st, &c, &indices_key,
+ &decoder_space_usage] {
+ if (should_add_elem) {
+ emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
+ add_elem(c, elem, decoder_space_usage);
+ } else {
+ emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
+ }
+ };
/* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
@@ -542,8 +543,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
- emit(c, dynidx(c, indices_key), elem, st);
- maybe_add(c, elem, decoder_space_usage);
+ emit_maybe_add();
return;
}
@@ -552,20 +552,23 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
- emit(c, dynidx(c, indices_key), elem, st);
- maybe_add(c, elem, decoder_space_usage);
+ emit_maybe_add();
return;
}
/* no elem, key in the table... fall back to literal emission */
- bool should_add_key =
+ const bool should_add_key =
!elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE;
- emit = (should_add_elem || should_add_key) ? emit_lithdr_incidx_v
- : emit_lithdr_noidx_v;
- maybe_add =
- should_add_elem ? add_elem : (should_add_key ? add_key : add_nothing);
- emit(c, 0, elem, st);
- maybe_add(c, elem, decoder_space_usage);
+ if (should_add_elem || should_add_key) {
+ emit_lithdr_incidx_v(c, 0, elem, st);
+ } else {
+ emit_lithdr_noidx_v(c, 0, elem, st);
+ }
+ if (should_add_elem) {
+ add_elem(c, elem, decoder_space_usage);
+ } else if (should_add_key) {
+ add_key(c, elem, decoder_space_usage);
+ }
}
#define STRLEN_LIT(x) (sizeof(x) - 1)
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
index 4d7dfd900f..dca15e7680 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
@@ -27,18 +27,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-void grpc_chttp2_incoming_metadata_buffer_init(
- grpc_chttp2_incoming_metadata_buffer* buffer, gpr_arena* arena) {
- buffer->arena = arena;
- grpc_metadata_batch_init(&buffer->batch);
- buffer->batch.deadline = GRPC_MILLIS_INF_FUTURE;
-}
-
-void grpc_chttp2_incoming_metadata_buffer_destroy(
- grpc_chttp2_incoming_metadata_buffer* buffer) {
- grpc_metadata_batch_destroy(&buffer->batch);
-}
-
grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
buffer->size += GRPC_MDELEM_LENGTH(elem);
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index d029cf00d4..c551b3cc8b 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -23,17 +23,20 @@
#include "src/core/lib/transport/transport.h"
-typedef struct {
+struct grpc_chttp2_incoming_metadata_buffer {
+ grpc_chttp2_incoming_metadata_buffer(gpr_arena* arena) : arena(arena) {
+ grpc_metadata_batch_init(&batch);
+ batch.deadline = GRPC_MILLIS_INF_FUTURE;
+ }
+ ~grpc_chttp2_incoming_metadata_buffer() {
+ grpc_metadata_batch_destroy(&batch);
+ }
+
gpr_arena* arena;
grpc_metadata_batch batch;
- size_t size; // total size of metadata
-} grpc_chttp2_incoming_metadata_buffer;
-
-/** assumes everything initially zeroed */
-void grpc_chttp2_incoming_metadata_buffer_init(
- grpc_chttp2_incoming_metadata_buffer* buffer, gpr_arena* arena);
-void grpc_chttp2_incoming_metadata_buffer_destroy(
- grpc_chttp2_incoming_metadata_buffer* buffer);
+ size_t size = 0; // total size of metadata
+};
+
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch);
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index ff26dd9255..341f5b3977 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -45,6 +45,10 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/transport_impl.h"
+namespace grpc_core {
+class ContextList;
+}
+
/* streams are kept in various linked lists depending on what things need to
happen to them... this enum labels each list */
typedef enum {
@@ -103,8 +107,8 @@ const char* grpc_chttp2_initiate_write_reason_string(
grpc_chttp2_initiate_write_reason reason);
typedef struct {
- grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT];
- uint64_t inflight_id;
+ grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT] = {};
+ uint64_t inflight_id = 0;
} grpc_chttp2_ping_queue;
typedef struct {
@@ -232,8 +236,12 @@ class Chttp2IncomingByteStream : public ByteStream {
// alone for now. We can revisit this once we're able to link against
// libc++, at which point we can eliminate New<> and Delete<> and
// switch to std::shared_ptr<>.
- void Ref();
- void Unref();
+ void Ref() { refs_.Ref(); }
+ void Unref() {
+ if (refs_.Unref()) {
+ grpc_core::Delete(this);
+ }
+ }
void PublishError(grpc_error* error);
@@ -252,7 +260,7 @@ class Chttp2IncomingByteStream : public ByteStream {
grpc_chttp2_transport* transport_; // Immutable.
grpc_chttp2_stream* stream_; // Immutable.
- gpr_refcount refs_;
+ grpc_core::RefCount refs_;
/* Accessed only by transport thread when stream->pending_byte_stream == false
* Accessed only by application thread when stream->pending_byte_stream ==
@@ -280,34 +288,41 @@ typedef enum {
} grpc_chttp2_keepalive_state;
struct grpc_chttp2_transport {
+ grpc_chttp2_transport(const grpc_channel_args* channel_args,
+ grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* resource_user);
+ ~grpc_chttp2_transport();
+
grpc_transport base; /* must be first */
- gpr_refcount refs;
+ grpc_core::RefCount refs;
grpc_endpoint* ep;
char* peer_string;
+ grpc_resource_user* resource_user;
+
grpc_combiner* combiner;
- grpc_closure* notify_on_receive_settings;
+ grpc_closure* notify_on_receive_settings = nullptr;
/** write execution state of the transport */
- grpc_chttp2_write_state write_state;
+ grpc_chttp2_write_state write_state = GRPC_CHTTP2_WRITE_STATE_IDLE;
/** is this the first write in a series of writes?
set when we initiate writing from idle, cleared when we
initiate writing from writing+more */
- bool is_first_write_in_batch;
+ bool is_first_write_in_batch = false;
/** is the transport destroying itself? */
- uint8_t destroying;
+ uint8_t destroying = false;
/** has the upper layer closed the transport? */
- grpc_error* closed_with_error;
+ grpc_error* closed_with_error = GRPC_ERROR_NONE;
/** is there a read request to the endpoint outstanding? */
- uint8_t endpoint_reading;
+ uint8_t endpoint_reading = 1;
- grpc_chttp2_optimization_target opt_target;
+ grpc_chttp2_optimization_target opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
/** various lists of streams */
- grpc_chttp2_stream_list lists[STREAM_LIST_COUNT];
+ grpc_chttp2_stream_list lists[STREAM_LIST_COUNT] = {};
/** maps stream id to grpc_chttp2_stream objects */
grpc_chttp2_stream_map stream_map;
@@ -324,7 +339,7 @@ struct grpc_chttp2_transport {
/** address to place a newly accepted stream - set and unset by
grpc_chttp2_parsing_accept_stream; used by init_stream to
publish the accepted server stream */
- grpc_chttp2_stream** accepting_stream;
+ grpc_chttp2_stream** accepting_stream = nullptr;
struct {
/* accept stream callback */
@@ -348,41 +363,43 @@ struct grpc_chttp2_transport {
/** how much data are we willing to buffer when the WRITE_BUFFER_HINT is set?
*/
- uint32_t write_buffer_size;
+ uint32_t write_buffer_size = grpc_core::chttp2::kDefaultWindow;
/** Set to a grpc_error object if a goaway frame is received. By default, set
* to GRPC_ERROR_NONE */
- grpc_error* goaway_error;
+ grpc_error* goaway_error = GRPC_ERROR_NONE;
- grpc_chttp2_sent_goaway_state sent_goaway_state;
+ grpc_chttp2_sent_goaway_state sent_goaway_state = GRPC_CHTTP2_NO_GOAWAY_SEND;
/** are the local settings dirty and need to be sent? */
- bool dirtied_local_settings;
+ bool dirtied_local_settings = true;
/** have local settings been sent? */
- bool sent_local_settings;
- /** bitmask of setting indexes to send out */
- uint32_t force_send_settings;
+ bool sent_local_settings = false;
+ /** bitmask of setting indexes to send out
+ Hack: it's common for implementations to assume 65536 bytes initial send
+ window -- this should by rights be 0 */
+ uint32_t force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
/** settings values */
uint32_t settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
/** what is the next stream id to be allocated by this peer?
copied to next_stream_id in parsing when parsing commences */
- uint32_t next_stream_id;
+ uint32_t next_stream_id = 0;
/** last new stream id */
- uint32_t last_new_stream_id;
+ uint32_t last_new_stream_id = 0;
/** ping queues for various ping insertion points */
- grpc_chttp2_ping_queue ping_queue;
+ grpc_chttp2_ping_queue ping_queue = grpc_chttp2_ping_queue();
grpc_chttp2_repeated_ping_policy ping_policy;
grpc_chttp2_repeated_ping_state ping_state;
- uint64_t ping_ctr; /* unique id for pings */
+ uint64_t ping_ctr = 0; /* unique id for pings */
grpc_closure retry_initiate_ping_locked;
/** ping acks */
- size_t ping_ack_count;
- size_t ping_ack_capacity;
- uint64_t* ping_acks;
+ size_t ping_ack_count = 0;
+ size_t ping_ack_capacity = 0;
+ uint64_t* ping_acks = nullptr;
grpc_chttp2_server_ping_recv_state ping_recv_state;
/** parser for headers */
@@ -408,22 +425,22 @@ struct grpc_chttp2_transport {
int64_t initial_window_update = 0;
/* deframing */
- grpc_chttp2_deframe_transport_state deframe_state;
- uint8_t incoming_frame_type;
- uint8_t incoming_frame_flags;
- uint8_t header_eof;
- bool is_first_frame;
- uint32_t expect_continuation_stream_id;
- uint32_t incoming_frame_size;
- uint32_t incoming_stream_id;
+ grpc_chttp2_deframe_transport_state deframe_state = GRPC_DTS_CLIENT_PREFIX_0;
+ uint8_t incoming_frame_type = 0;
+ uint8_t incoming_frame_flags = 0;
+ uint8_t header_eof = 0;
+ bool is_first_frame = true;
+ uint32_t expect_continuation_stream_id = 0;
+ uint32_t incoming_frame_size = 0;
+ uint32_t incoming_stream_id = 0;
/* active parser */
- void* parser_data;
- grpc_chttp2_stream* incoming_stream;
+ void* parser_data = nullptr;
+ grpc_chttp2_stream* incoming_stream = nullptr;
grpc_error* (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
grpc_chttp2_stream* s, grpc_slice slice, int is_last);
- grpc_chttp2_write_cb* write_cb_pool;
+ grpc_chttp2_write_cb* write_cb_pool = nullptr;
/* bdp estimator */
grpc_closure next_bdp_ping_timer_expired_locked;
@@ -432,23 +449,23 @@ struct grpc_chttp2_transport {
/* if non-NULL, close the transport with this error when writes are finished
*/
- grpc_error* close_transport_on_writes_finished;
+ grpc_error* close_transport_on_writes_finished = GRPC_ERROR_NONE;
/* a list of closures to run after writes are finished */
- grpc_closure_list run_after_write;
+ grpc_closure_list run_after_write = GRPC_CLOSURE_LIST_INIT;
/* buffer pool state */
/** have we scheduled a benign cleanup? */
- bool benign_reclaimer_registered;
+ bool benign_reclaimer_registered = false;
/** have we scheduled a destructive cleanup? */
- bool destructive_reclaimer_registered;
+ bool destructive_reclaimer_registered = false;
/** benign cleanup closure */
grpc_closure benign_reclaimer_locked;
/** destructive cleanup closure */
grpc_closure destructive_reclaimer_locked;
/* next bdp ping timer */
- bool have_next_bdp_ping_timer;
+ bool have_next_bdp_ping_timer = false;
grpc_timer next_bdp_ping_timer;
/* keep-alive ping support */
@@ -469,12 +486,12 @@ struct grpc_chttp2_transport {
/** grace period for a ping to complete before watchdog kicks in */
grpc_millis keepalive_timeout;
/** if keepalive pings are allowed when there's no outstanding streams */
- bool keepalive_permit_without_calls;
+ bool keepalive_permit_without_calls = false;
/** keep-alive state machine state */
grpc_chttp2_keepalive_state keepalive_state;
-
+ grpc_core::ContextList* cl = nullptr;
grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> channelz_socket;
- uint32_t num_messages_in_next_write;
+ uint32_t num_messages_in_next_write = 0;
};
typedef enum {
@@ -485,6 +502,11 @@ typedef enum {
} grpc_published_metadata_method;
struct grpc_chttp2_stream {
+ grpc_chttp2_stream(grpc_chttp2_transport* t, grpc_stream_refcount* refcount,
+ const void* server_data, gpr_arena* arena);
+ ~grpc_chttp2_stream();
+
+ void* context;
grpc_chttp2_transport* t;
grpc_stream_refcount* refcount;
@@ -492,63 +514,63 @@ struct grpc_chttp2_stream {
grpc_closure* destroy_stream_arg;
grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
- uint8_t included[STREAM_LIST_COUNT];
+ uint8_t included[STREAM_LIST_COUNT] = {};
/** HTTP2 stream id for this stream, or zero if one has not been assigned */
- uint32_t id;
+ uint32_t id = 0;
/** things the upper layers would like to send */
- grpc_metadata_batch* send_initial_metadata;
- grpc_closure* send_initial_metadata_finished;
- grpc_metadata_batch* send_trailing_metadata;
- grpc_closure* send_trailing_metadata_finished;
+ grpc_metadata_batch* send_initial_metadata = nullptr;
+ grpc_closure* send_initial_metadata_finished = nullptr;
+ grpc_metadata_batch* send_trailing_metadata = nullptr;
+ grpc_closure* send_trailing_metadata_finished = nullptr;
grpc_core::OrphanablePtr<grpc_core::ByteStream> fetching_send_message;
- uint32_t fetched_send_message_length;
- grpc_slice fetching_slice;
+ uint32_t fetched_send_message_length = 0;
+ grpc_slice fetching_slice = grpc_empty_slice();
int64_t next_message_end_offset;
- int64_t flow_controlled_bytes_written;
- int64_t flow_controlled_bytes_flowed;
+ int64_t flow_controlled_bytes_written = 0;
+ int64_t flow_controlled_bytes_flowed = 0;
grpc_closure complete_fetch_locked;
- grpc_closure* fetching_send_message_finished;
+ grpc_closure* fetching_send_message_finished = nullptr;
grpc_metadata_batch* recv_initial_metadata;
- grpc_closure* recv_initial_metadata_ready;
- bool* trailing_metadata_available;
+ grpc_closure* recv_initial_metadata_ready = nullptr;
+ bool* trailing_metadata_available = nullptr;
grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
- grpc_closure* recv_message_ready;
+ grpc_closure* recv_message_ready = nullptr;
grpc_metadata_batch* recv_trailing_metadata;
- grpc_closure* recv_trailing_metadata_finished;
+ grpc_closure* recv_trailing_metadata_finished = nullptr;
- grpc_transport_stream_stats* collecting_stats;
- grpc_transport_stream_stats stats;
+ grpc_transport_stream_stats* collecting_stats = nullptr;
+ grpc_transport_stream_stats stats = grpc_transport_stream_stats();
/** Is this stream closed for writing. */
- bool write_closed;
+ bool write_closed = false;
/** Is this stream reading half-closed. */
- bool read_closed;
+ bool read_closed = false;
/** Are all published incoming byte streams closed. */
- bool all_incoming_byte_streams_finished;
+ bool all_incoming_byte_streams_finished = false;
/** Has this stream seen an error.
If true, then pending incoming frames can be thrown away. */
- bool seen_error;
+ bool seen_error = false;
/** Are we buffering writes on this stream? If yes, we won't become writable
until there's enough queued up in the flow_controlled_buffer */
- bool write_buffering;
+ bool write_buffering = false;
/** Has trailing metadata been received. */
- bool received_trailing_metadata;
+ bool received_trailing_metadata = false;
/* have we sent or received the EOS bit? */
- bool eos_received;
- bool eos_sent;
+ bool eos_received = false;
+ bool eos_sent = false;
/** the error that resulted in this stream being read-closed */
- grpc_error* read_closed_error;
+ grpc_error* read_closed_error = GRPC_ERROR_NONE;
/** the error that resulted in this stream being write-closed */
- grpc_error* write_closed_error;
+ grpc_error* write_closed_error = GRPC_ERROR_NONE;
- grpc_published_metadata_method published_metadata[2];
- bool final_metadata_requested;
+ grpc_published_metadata_method published_metadata[2] = {};
+ bool final_metadata_requested = false;
grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
@@ -558,33 +580,33 @@ struct grpc_chttp2_stream {
* Accessed only by application thread when stream->pending_byte_stream ==
* true */
grpc_slice_buffer unprocessed_incoming_frames_buffer;
- grpc_closure* on_next; /* protected by t combiner */
- bool pending_byte_stream; /* protected by t combiner */
+ grpc_closure* on_next = nullptr; /* protected by t combiner */
+ bool pending_byte_stream = false; /* protected by t combiner */
// cached length of buffer to be used by the transport thread in cases where
// stream->pending_byte_stream == true. The value is saved before
// application threads are allowed to modify
// unprocessed_incoming_frames_buffer
- size_t unprocessed_incoming_frames_buffer_cached_length;
+ size_t unprocessed_incoming_frames_buffer_cached_length = 0;
grpc_closure reset_byte_stream;
- grpc_error* byte_stream_error; /* protected by t combiner */
- bool received_last_frame; /* protected by t combiner */
+ grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */
+ bool received_last_frame = false; /* protected by t combiner */
- grpc_millis deadline;
+ grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
/** saw some stream level error */
- grpc_error* forced_close_error;
+ grpc_error* forced_close_error = GRPC_ERROR_NONE;
/** how many header frames have we received? */
- uint8_t header_frames_received;
+ uint8_t header_frames_received = 0;
/** parsing state for data frames */
/* Accessed only by transport thread when stream->pending_byte_stream == false
* Accessed only by application thread when stream->pending_byte_stream ==
* true */
grpc_chttp2_data_parser data_parser;
/** number of bytes received - reset at end of parse thread execution */
- int64_t received_bytes;
+ int64_t received_bytes = 0;
- bool sent_initial_metadata;
- bool sent_trailing_metadata;
+ bool sent_initial_metadata = false;
+ bool sent_trailing_metadata = false;
grpc_core::PolymorphicManualConstructor<
grpc_core::chttp2::StreamFlowControlBase,
@@ -594,32 +616,38 @@ struct grpc_chttp2_stream {
grpc_slice_buffer flow_controlled_buffer;
- grpc_chttp2_write_cb* on_flow_controlled_cbs;
- grpc_chttp2_write_cb* on_write_finished_cbs;
- grpc_chttp2_write_cb* finish_after_write;
- size_t sending_bytes;
+ grpc_chttp2_write_cb* on_flow_controlled_cbs = nullptr;
+ grpc_chttp2_write_cb* on_write_finished_cbs = nullptr;
+ grpc_chttp2_write_cb* finish_after_write = nullptr;
+ size_t sending_bytes = 0;
/* Stream compression method to be used. */
- grpc_stream_compression_method stream_compression_method;
+ grpc_stream_compression_method stream_compression_method =
+ GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS;
/* Stream decompression method to be used. */
- grpc_stream_compression_method stream_decompression_method;
+ grpc_stream_compression_method stream_decompression_method =
+ GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS;
/** Stream compression decompress context */
- grpc_stream_compression_context* stream_decompression_ctx;
+ grpc_stream_compression_context* stream_decompression_ctx = nullptr;
/** Stream compression compress context */
- grpc_stream_compression_context* stream_compression_ctx;
+ grpc_stream_compression_context* stream_compression_ctx = nullptr;
/** Buffer storing data that is compressed but not sent */
grpc_slice_buffer compressed_data_buffer;
/** Amount of uncompressed bytes sent out when compressed_data_buffer is
* emptied */
- size_t uncompressed_data_size;
+ size_t uncompressed_data_size = 0;
/** Temporary buffer storing decompressed data */
grpc_slice_buffer decompressed_data_buffer;
/** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed
*/
- bool unprocessed_incoming_frames_decompressed;
+ bool unprocessed_incoming_frames_decompressed = false;
+ /** Whether the bytes needs to be traced using Fathom */
+ bool traced = false;
/** gRPC header bytes that are already decompressed */
- size_t decompressed_header_bytes;
+ size_t decompressed_header_bytes = 0;
+ /** Byte counter for number of bytes written */
+ size_t byte_counter = 0;
};
/** Transport writing call flow:
@@ -764,15 +792,29 @@ void grpc_chttp2_stream_unref(grpc_chttp2_stream* s);
grpc_chttp2_ref_transport(t, r, __FILE__, __LINE__)
#define GRPC_CHTTP2_UNREF_TRANSPORT(t, r) \
grpc_chttp2_unref_transport(t, r, __FILE__, __LINE__)
-void grpc_chttp2_unref_transport(grpc_chttp2_transport* t, const char* reason,
- const char* file, int line);
-void grpc_chttp2_ref_transport(grpc_chttp2_transport* t, const char* reason,
- const char* file, int line);
+inline void grpc_chttp2_unref_transport(grpc_chttp2_transport* t,
+ const char* reason, const char* file,
+ int line) {
+ if (t->refs.Unref(grpc_core::DebugLocation(file, line), reason)) {
+ grpc_core::Delete(t);
+ }
+}
+inline void grpc_chttp2_ref_transport(grpc_chttp2_transport* t,
+ const char* reason, const char* file,
+ int line) {
+ t->refs.Ref(grpc_core::DebugLocation(file, line), reason);
+}
#else
#define GRPC_CHTTP2_REF_TRANSPORT(t, r) grpc_chttp2_ref_transport(t)
#define GRPC_CHTTP2_UNREF_TRANSPORT(t, r) grpc_chttp2_unref_transport(t)
-void grpc_chttp2_unref_transport(grpc_chttp2_transport* t);
-void grpc_chttp2_ref_transport(grpc_chttp2_transport* t);
+inline void grpc_chttp2_unref_transport(grpc_chttp2_transport* t) {
+ if (t->refs.Unref()) {
+ grpc_core::Delete(t);
+ }
+}
+inline void grpc_chttp2_ref_transport(grpc_chttp2_transport* t) {
+ t->refs.Ref();
+}
#endif
void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id);
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index d533989444..265d3365d3 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -18,6 +18,7 @@
#include <grpc/support/port_platform.h>
+#include "src/core/ext/transport/chttp2/transport/context_list.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include <limits.h>
@@ -362,6 +363,7 @@ class DataSendContext {
grpc_chttp2_encode_data(s_->id, &s_->compressed_data_buffer, send_bytes,
is_last_frame_, &s_->stats.outgoing, &t_->outbuf);
s_->flow_control->SentData(send_bytes);
+ s_->byte_counter += send_bytes;
if (s_->compressed_data_buffer.length == 0) {
s_->sending_bytes += s_->uncompressed_data_size;
}
@@ -496,6 +498,9 @@ class StreamWriteContext {
data_send_context.CompressMoreBytes();
}
}
+ if (s_->traced && grpc_endpoint_can_track_err(t_->ep)) {
+ grpc_core::ContextList::Append(&t_->cl, s_);
+ }
write_context_->ResetPingClock();
if (data_send_context.is_last_frame()) {
SentLastFrame();
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc
index 81e2634e3a..349d8681d5 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.cc
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -111,16 +111,21 @@ typedef struct grpc_cronet_transport grpc_cronet_transport;
/* TODO (makdharma): reorder structure for memory efficiency per
http://www.catb.org/esr/structure-packing/#_structure_reordering: */
struct read_state {
+ read_state(gpr_arena* arena)
+ : trailing_metadata(arena), initial_metadata(arena) {
+ grpc_slice_buffer_init(&read_slice_buffer);
+ }
+
/* vars to store data coming from server */
- char* read_buffer;
- bool length_field_received;
- int received_bytes;
- int remaining_bytes;
- int length_field;
- bool compressed;
- char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES];
- char* payload_field;
- bool read_stream_closed;
+ char* read_buffer = nullptr;
+ bool length_field_received = false;
+ int received_bytes = 0;
+ int remaining_bytes = 0;
+ int length_field = 0;
+ bool compressed = 0;
+ char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES] = {};
+ char* payload_field = nullptr;
+ bool read_stream_closed = 0;
/* vars for holding data destined for the application */
grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sbs;
@@ -128,59 +133,71 @@ struct read_state {
/* vars for trailing metadata */
grpc_chttp2_incoming_metadata_buffer trailing_metadata;
- bool trailing_metadata_valid;
+ bool trailing_metadata_valid = false;
/* vars for initial metadata */
grpc_chttp2_incoming_metadata_buffer initial_metadata;
};
struct write_state {
- char* write_buffer;
+ char* write_buffer = nullptr;
};
/* track state of one stream op */
struct op_state {
- bool state_op_done[OP_NUM_OPS];
- bool state_callback_received[OP_NUM_OPS];
+ op_state(gpr_arena* arena) : rs(arena) {}
+
+ bool state_op_done[OP_NUM_OPS] = {};
+ bool state_callback_received[OP_NUM_OPS] = {};
/* A non-zero gRPC status code has been seen */
- bool fail_state;
+ bool fail_state = false;
/* Transport is discarding all buffered messages */
- bool flush_read;
- bool flush_cronet_when_ready;
- bool pending_write_for_trailer;
- bool pending_send_message;
+ bool flush_read = false;
+ bool flush_cronet_when_ready = false;
+ bool pending_write_for_trailer = false;
+ bool pending_send_message = false;
/* User requested RECV_TRAILING_METADATA */
- bool pending_recv_trailing_metadata;
+ bool pending_recv_trailing_metadata = false;
/* Cronet has not issued a callback of a bidirectional read */
- bool pending_read_from_cronet;
- grpc_error* cancel_error;
+ bool pending_read_from_cronet = false;
+ grpc_error* cancel_error = GRPC_ERROR_NONE;
/* data structure for storing data coming from server */
struct read_state rs;
/* data structure for storing data going to the server */
struct write_state ws;
};
+struct stream_obj;
+
struct op_and_state {
+ op_and_state(stream_obj* s, const grpc_transport_stream_op_batch& op);
+
grpc_transport_stream_op_batch op;
struct op_state state;
- bool done;
- struct stream_obj* s; /* Pointer back to the stream object */
- struct op_and_state* next; /* next op_and_state in the linked list */
+ bool done = false;
+ struct stream_obj* s; /* Pointer back to the stream object */
+ /* next op_and_state in the linked list */
+ struct op_and_state* next;
};
struct op_storage {
- int num_pending_ops;
- struct op_and_state* head;
+ int num_pending_ops = 0;
+ struct op_and_state* head = nullptr;
};
struct stream_obj {
+ stream_obj(grpc_transport* gt, grpc_stream* gs,
+ grpc_stream_refcount* refcount, gpr_arena* arena);
+ ~stream_obj();
+
gpr_arena* arena;
- struct op_and_state* oas;
- grpc_transport_stream_op_batch* curr_op;
+ struct op_and_state* oas = nullptr;
+ grpc_transport_stream_op_batch* curr_op = nullptr;
grpc_cronet_transport* curr_ct;
grpc_stream* curr_gs;
- bidirectional_stream* cbs;
- bidirectional_stream_header_array header_array;
+ bidirectional_stream* cbs = nullptr;
+ bidirectional_stream_header_array header_array =
+ bidirectional_stream_header_array(); // Zero-initialize the structure.
/* Stream level state. Some state will be tracked both at stream and stream_op
* level */
@@ -195,7 +212,6 @@ struct stream_obj {
/* Refcount object of the stream */
grpc_stream_refcount* refcount;
};
-typedef struct stream_obj stream_obj;
#ifndef NDEBUG
#define GRPC_CRONET_STREAM_REF(stream, reason) \
@@ -306,6 +322,10 @@ static grpc_error* make_error_with_desc(int error_code, const char* desc) {
return error;
}
+inline op_and_state::op_and_state(stream_obj* s,
+ const grpc_transport_stream_op_batch& op)
+ : op(op), state(s->arena), s(s), next(s->storage.head) {}
+
/*
Add a new stream op to op storage.
*/
@@ -314,14 +334,8 @@ static void add_to_storage(struct stream_obj* s,
struct op_storage* storage = &s->storage;
/* add new op at the beginning of the linked list. The memory is freed
in remove_from_storage */
- struct op_and_state* new_op = static_cast<struct op_and_state*>(
- gpr_malloc(sizeof(struct op_and_state)));
- memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op_batch));
- memset(&new_op->state, 0, sizeof(new_op->state));
- new_op->s = s;
- new_op->done = false;
+ op_and_state* new_op = grpc_core::New<op_and_state>(s, *op);
gpr_mu_lock(&s->mu);
- new_op->next = storage->head;
storage->head = new_op;
storage->num_pending_ops++;
if (op->send_message) {
@@ -347,7 +361,7 @@ static void remove_from_storage(struct stream_obj* s,
}
if (s->storage.head == oas) {
s->storage.head = oas->next;
- gpr_free(oas);
+ grpc_core::Delete(oas);
s->storage.num_pending_ops--;
CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
s->storage.num_pending_ops);
@@ -358,7 +372,7 @@ static void remove_from_storage(struct stream_obj* s,
s->storage.num_pending_ops--;
CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
s->storage.num_pending_ops);
- gpr_free(oas);
+ grpc_core::Delete(oas);
break;
} else if (GPR_UNLIKELY(curr->next == nullptr)) {
CRONET_LOG(GPR_ERROR, "Reached end of LL and did not find op to free");
@@ -540,10 +554,6 @@ static void on_response_headers_received(
}
gpr_mu_lock(&s->mu);
- memset(&s->state.rs.initial_metadata, 0,
- sizeof(s->state.rs.initial_metadata));
- grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata,
- s->arena);
convert_cronet_array_to_metadata(headers, &s->state.rs.initial_metadata);
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
@@ -634,11 +644,7 @@ static void on_response_trailers_received(
stream_obj* s = static_cast<stream_obj*>(stream->annotation);
grpc_cronet_transport* t = s->curr_ct;
gpr_mu_lock(&s->mu);
- memset(&s->state.rs.trailing_metadata, 0,
- sizeof(s->state.rs.trailing_metadata));
s->state.rs.trailing_metadata_valid = false;
- grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata,
- s->arena);
convert_cronet_array_to_metadata(trailers, &s->state.rs.trailing_metadata);
if (trailers->count > 0) {
s->state.rs.trailing_metadata_valid = true;
@@ -1354,36 +1360,28 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
Functions used by upper layers to access transport functionality.
*/
+inline stream_obj::stream_obj(grpc_transport* gt, grpc_stream* gs,
+ grpc_stream_refcount* refcount, gpr_arena* arena)
+ : arena(arena),
+ curr_ct(reinterpret_cast<grpc_cronet_transport*>(gt)),
+ curr_gs(gs),
+ state(arena),
+ refcount(refcount) {
+ GRPC_CRONET_STREAM_REF(this, "cronet transport");
+ gpr_mu_init(&mu);
+}
+
+inline stream_obj::~stream_obj() {
+ null_and_maybe_free_read_buffer(this);
+ /* Clean up read_slice_buffer in case there is unread data. */
+ grpc_slice_buffer_destroy_internal(&state.rs.read_slice_buffer);
+ GRPC_ERROR_UNREF(state.cancel_error);
+}
+
static int init_stream(grpc_transport* gt, grpc_stream* gs,
grpc_stream_refcount* refcount, const void* server_data,
gpr_arena* arena) {
- stream_obj* s = reinterpret_cast<stream_obj*>(gs);
-
- s->refcount = refcount;
- GRPC_CRONET_STREAM_REF(s, "cronet transport");
- memset(&s->storage, 0, sizeof(s->storage));
- s->storage.head = nullptr;
- memset(&s->state, 0, sizeof(s->state));
- s->curr_op = nullptr;
- s->cbs = nullptr;
- memset(&s->header_array, 0, sizeof(s->header_array));
- memset(&s->state.rs, 0, sizeof(s->state.rs));
- memset(&s->state.ws, 0, sizeof(s->state.ws));
- memset(s->state.state_op_done, 0, sizeof(s->state.state_op_done));
- memset(s->state.state_callback_received, 0,
- sizeof(s->state.state_callback_received));
- s->state.fail_state = s->state.flush_read = false;
- s->state.cancel_error = nullptr;
- s->state.flush_cronet_when_ready = s->state.pending_write_for_trailer = false;
- s->state.pending_send_message = false;
- s->state.pending_recv_trailing_metadata = false;
- s->state.pending_read_from_cronet = false;
-
- s->curr_gs = gs;
- s->curr_ct = reinterpret_cast<grpc_cronet_transport*>(gt);
- s->arena = arena;
-
- gpr_mu_init(&s->mu);
+ new (gs) stream_obj(gt, gs, refcount, arena);
return 0;
}
@@ -1426,10 +1424,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
grpc_closure* then_schedule_closure) {
stream_obj* s = reinterpret_cast<stream_obj*>(gs);
- null_and_maybe_free_read_buffer(s);
- /* Clean up read_slice_buffer in case there is unread data. */
- grpc_slice_buffer_destroy_internal(&s->state.rs.read_slice_buffer);
- GRPC_ERROR_UNREF(s->state.cancel_error);
+ s->~stream_obj();
GRPC_CLOSURE_SCHED(then_schedule_closure, GRPC_ERROR_NONE);
}
diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc
index 9dbd095843..0b9bf5dd11 100644
--- a/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/src/core/ext/transport/inproc/inproc_transport.cc
@@ -40,18 +40,68 @@
if (grpc_inproc_trace.enabled()) gpr_log(__VA_ARGS__); \
} while (0)
-static grpc_slice g_empty_slice;
-static grpc_slice g_fake_path_key;
-static grpc_slice g_fake_path_value;
-static grpc_slice g_fake_auth_key;
-static grpc_slice g_fake_auth_value;
+namespace {
+grpc_slice g_empty_slice;
+grpc_slice g_fake_path_key;
+grpc_slice g_fake_path_value;
+grpc_slice g_fake_auth_key;
+grpc_slice g_fake_auth_value;
+
+struct inproc_stream;
+bool cancel_stream_locked(inproc_stream* s, grpc_error* error);
+void op_state_machine(void* arg, grpc_error* error);
+void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
+ bool is_initial);
+grpc_error* fill_in_metadata(inproc_stream* s,
+ const grpc_metadata_batch* metadata,
+ uint32_t flags, grpc_metadata_batch* out_md,
+ uint32_t* outflags, bool* markfilled);
+
+struct shared_mu {
+ shared_mu() {
+ // Share one lock between both sides since both sides get affected
+ gpr_mu_init(&mu);
+ gpr_ref_init(&refs, 2);
+ }
-typedef struct {
gpr_mu mu;
gpr_refcount refs;
-} shared_mu;
+};
+
+struct inproc_transport {
+ inproc_transport(const grpc_transport_vtable* vtable, shared_mu* mu,
+ bool is_client)
+ : mu(mu), is_client(is_client) {
+ base.vtable = vtable;
+ // Start each side of transport with 2 refs since they each have a ref
+ // to the other
+ gpr_ref_init(&refs, 2);
+ grpc_connectivity_state_init(&connectivity, GRPC_CHANNEL_READY,
+ is_client ? "inproc_client" : "inproc_server");
+ }
+
+ ~inproc_transport() {
+ grpc_connectivity_state_destroy(&connectivity);
+ if (gpr_unref(&mu->refs)) {
+ gpr_free(mu);
+ }
+ }
+
+ void ref() {
+ INPROC_LOG(GPR_INFO, "ref_transport %p", this);
+ gpr_ref(&refs);
+ }
+
+ void unref() {
+ INPROC_LOG(GPR_INFO, "unref_transport %p", this);
+ if (!gpr_unref(&refs)) {
+ return;
+ }
+ INPROC_LOG(GPR_INFO, "really_destroy_transport %p", this);
+ this->~inproc_transport();
+ gpr_free(this);
+ }
-typedef struct inproc_transport {
grpc_transport base;
shared_mu* mu;
gpr_refcount refs;
@@ -60,128 +110,174 @@ typedef struct inproc_transport {
void (*accept_stream_cb)(void* user_data, grpc_transport* transport,
const void* server_data);
void* accept_stream_data;
- bool is_closed;
+ bool is_closed = false;
struct inproc_transport* other_side;
- struct inproc_stream* stream_list;
-} inproc_transport;
+ struct inproc_stream* stream_list = nullptr;
+};
+
+struct inproc_stream {
+ inproc_stream(inproc_transport* t, grpc_stream_refcount* refcount,
+ const void* server_data, gpr_arena* arena)
+ : t(t), refs(refcount), arena(arena) {
+ // Ref this stream right now for ctor and list.
+ ref("inproc_init_stream:init");
+ ref("inproc_init_stream:list");
+
+ grpc_metadata_batch_init(&to_read_initial_md);
+ grpc_metadata_batch_init(&to_read_trailing_md);
+ GRPC_CLOSURE_INIT(&op_closure, op_state_machine, this,
+ grpc_schedule_on_exec_ctx);
+ grpc_metadata_batch_init(&write_buffer_initial_md);
+ grpc_metadata_batch_init(&write_buffer_trailing_md);
+
+ stream_list_prev = nullptr;
+ gpr_mu_lock(&t->mu->mu);
+ stream_list_next = t->stream_list;
+ if (t->stream_list) {
+ t->stream_list->stream_list_prev = this;
+ }
+ t->stream_list = this;
+ gpr_mu_unlock(&t->mu->mu);
+
+ if (!server_data) {
+ t->ref();
+ inproc_transport* st = t->other_side;
+ st->ref();
+ other_side = nullptr; // will get filled in soon
+ // Pass the client-side stream address to the server-side for a ref
+ ref("inproc_init_stream:clt"); // ref it now on behalf of server
+ // side to avoid destruction
+ INPROC_LOG(GPR_INFO, "calling accept stream cb %p %p",
+ st->accept_stream_cb, st->accept_stream_data);
+ (*st->accept_stream_cb)(st->accept_stream_data, &st->base, (void*)this);
+ } else {
+ // This is the server-side and is being called through accept_stream_cb
+ inproc_stream* cs = (inproc_stream*)server_data;
+ other_side = cs;
+ // Ref the server-side stream on behalf of the client now
+ ref("inproc_init_stream:srv");
+
+ // Now we are about to affect the other side, so lock the transport
+ // to make sure that it doesn't get destroyed
+ gpr_mu_lock(&t->mu->mu);
+ cs->other_side = this;
+ // Now transfer from the other side's write_buffer if any to the to_read
+ // buffer
+ if (cs->write_buffer_initial_md_filled) {
+ fill_in_metadata(this, &cs->write_buffer_initial_md,
+ cs->write_buffer_initial_md_flags, &to_read_initial_md,
+ &to_read_initial_md_flags, &to_read_initial_md_filled);
+ deadline = GPR_MIN(deadline, cs->write_buffer_deadline);
+ grpc_metadata_batch_clear(&cs->write_buffer_initial_md);
+ cs->write_buffer_initial_md_filled = false;
+ }
+ if (cs->write_buffer_trailing_md_filled) {
+ fill_in_metadata(this, &cs->write_buffer_trailing_md, 0,
+ &to_read_trailing_md, nullptr,
+ &to_read_trailing_md_filled);
+ grpc_metadata_batch_clear(&cs->write_buffer_trailing_md);
+ cs->write_buffer_trailing_md_filled = false;
+ }
+ if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) {
+ cancel_other_error = cs->write_buffer_cancel_error;
+ cs->write_buffer_cancel_error = GRPC_ERROR_NONE;
+ }
+
+ gpr_mu_unlock(&t->mu->mu);
+ }
+ }
+
+ ~inproc_stream() {
+ GRPC_ERROR_UNREF(write_buffer_cancel_error);
+ GRPC_ERROR_UNREF(cancel_self_error);
+ GRPC_ERROR_UNREF(cancel_other_error);
+
+ if (recv_inited) {
+ grpc_slice_buffer_destroy_internal(&recv_message);
+ }
+
+ t->unref();
+
+ if (closure_at_destroy) {
+ GRPC_CLOSURE_SCHED(closure_at_destroy, GRPC_ERROR_NONE);
+ }
+ }
+
+#ifndef NDEBUG
+#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason)
+#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs, reason)
+#else
+#define STREAM_REF(refs, reason) grpc_stream_ref(refs)
+#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs)
+#endif
+ void ref(const char* reason) {
+ INPROC_LOG(GPR_INFO, "ref_stream %p %s", this, reason);
+ STREAM_REF(refs, reason);
+ }
+
+ void unref(const char* reason) {
+ INPROC_LOG(GPR_INFO, "unref_stream %p %s", this, reason);
+ STREAM_UNREF(refs, reason);
+ }
+#undef STREAM_REF
+#undef STREAM_UNREF
-typedef struct inproc_stream {
inproc_transport* t;
grpc_metadata_batch to_read_initial_md;
- uint32_t to_read_initial_md_flags;
- bool to_read_initial_md_filled;
+ uint32_t to_read_initial_md_flags = 0;
+ bool to_read_initial_md_filled = false;
grpc_metadata_batch to_read_trailing_md;
- bool to_read_trailing_md_filled;
- bool ops_needed;
- bool op_closure_scheduled;
+ bool to_read_trailing_md_filled = false;
+ bool ops_needed = false;
+ bool op_closure_scheduled = false;
grpc_closure op_closure;
// Write buffer used only during gap at init time when client-side
// stream is set up but server side stream is not yet set up
grpc_metadata_batch write_buffer_initial_md;
- bool write_buffer_initial_md_filled;
- uint32_t write_buffer_initial_md_flags;
- grpc_millis write_buffer_deadline;
+ bool write_buffer_initial_md_filled = false;
+ uint32_t write_buffer_initial_md_flags = 0;
+ grpc_millis write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
grpc_metadata_batch write_buffer_trailing_md;
- bool write_buffer_trailing_md_filled;
- grpc_error* write_buffer_cancel_error;
+ bool write_buffer_trailing_md_filled = false;
+ grpc_error* write_buffer_cancel_error = GRPC_ERROR_NONE;
struct inproc_stream* other_side;
- bool other_side_closed; // won't talk anymore
- bool write_buffer_other_side_closed; // on hold
+ bool other_side_closed = false; // won't talk anymore
+ bool write_buffer_other_side_closed = false; // on hold
grpc_stream_refcount* refs;
- grpc_closure* closure_at_destroy;
+ grpc_closure* closure_at_destroy = nullptr;
gpr_arena* arena;
- grpc_transport_stream_op_batch* send_message_op;
- grpc_transport_stream_op_batch* send_trailing_md_op;
- grpc_transport_stream_op_batch* recv_initial_md_op;
- grpc_transport_stream_op_batch* recv_message_op;
- grpc_transport_stream_op_batch* recv_trailing_md_op;
+ grpc_transport_stream_op_batch* send_message_op = nullptr;
+ grpc_transport_stream_op_batch* send_trailing_md_op = nullptr;
+ grpc_transport_stream_op_batch* recv_initial_md_op = nullptr;
+ grpc_transport_stream_op_batch* recv_message_op = nullptr;
+ grpc_transport_stream_op_batch* recv_trailing_md_op = nullptr;
grpc_slice_buffer recv_message;
grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> recv_stream;
- bool recv_inited;
+ bool recv_inited = false;
- bool initial_md_sent;
- bool trailing_md_sent;
- bool initial_md_recvd;
- bool trailing_md_recvd;
+ bool initial_md_sent = false;
+ bool trailing_md_sent = false;
+ bool initial_md_recvd = false;
+ bool trailing_md_recvd = false;
- bool closed;
+ bool closed = false;
- grpc_error* cancel_self_error;
- grpc_error* cancel_other_error;
+ grpc_error* cancel_self_error = GRPC_ERROR_NONE;
+ grpc_error* cancel_other_error = GRPC_ERROR_NONE;
- grpc_millis deadline;
+ grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
- bool listed;
+ bool listed = true;
struct inproc_stream* stream_list_prev;
struct inproc_stream* stream_list_next;
-} inproc_stream;
-
-static bool cancel_stream_locked(inproc_stream* s, grpc_error* error);
-static void op_state_machine(void* arg, grpc_error* error);
-
-static void ref_transport(inproc_transport* t) {
- INPROC_LOG(GPR_INFO, "ref_transport %p", t);
- gpr_ref(&t->refs);
-}
-
-static void really_destroy_transport(inproc_transport* t) {
- INPROC_LOG(GPR_INFO, "really_destroy_transport %p", t);
- grpc_connectivity_state_destroy(&t->connectivity);
- if (gpr_unref(&t->mu->refs)) {
- gpr_free(t->mu);
- }
- gpr_free(t);
-}
-
-static void unref_transport(inproc_transport* t) {
- INPROC_LOG(GPR_INFO, "unref_transport %p", t);
- if (gpr_unref(&t->refs)) {
- really_destroy_transport(t);
- }
-}
-
-#ifndef NDEBUG
-#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason)
-#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs, reason)
-#else
-#define STREAM_REF(refs, reason) grpc_stream_ref(refs)
-#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs)
-#endif
-
-static void ref_stream(inproc_stream* s, const char* reason) {
- INPROC_LOG(GPR_INFO, "ref_stream %p %s", s, reason);
- STREAM_REF(s->refs, reason);
-}
-
-static void unref_stream(inproc_stream* s, const char* reason) {
- INPROC_LOG(GPR_INFO, "unref_stream %p %s", s, reason);
- STREAM_UNREF(s->refs, reason);
-}
-
-static void really_destroy_stream(inproc_stream* s) {
- INPROC_LOG(GPR_INFO, "really_destroy_stream %p", s);
+};
- GRPC_ERROR_UNREF(s->write_buffer_cancel_error);
- GRPC_ERROR_UNREF(s->cancel_self_error);
- GRPC_ERROR_UNREF(s->cancel_other_error);
-
- if (s->recv_inited) {
- grpc_slice_buffer_destroy_internal(&s->recv_message);
- }
-
- unref_transport(s->t);
-
- if (s->closure_at_destroy) {
- GRPC_CLOSURE_SCHED(s->closure_at_destroy, GRPC_ERROR_NONE);
- }
-}
-
-static void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
- bool is_initial) {
+void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
+ bool is_initial) {
for (grpc_linked_mdelem* md = md_batch->list.head; md != nullptr;
md = md->next) {
char* key = grpc_slice_to_c_string(GRPC_MDKEY(md->md));
@@ -193,10 +289,10 @@ static void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
}
}
-static grpc_error* fill_in_metadata(inproc_stream* s,
- const grpc_metadata_batch* metadata,
- uint32_t flags, grpc_metadata_batch* out_md,
- uint32_t* outflags, bool* markfilled) {
+grpc_error* fill_in_metadata(inproc_stream* s,
+ const grpc_metadata_batch* metadata,
+ uint32_t flags, grpc_metadata_batch* out_md,
+ uint32_t* outflags, bool* markfilled) {
if (grpc_inproc_trace.enabled()) {
log_metadata(metadata, s->t->is_client, outflags != nullptr);
}
@@ -221,109 +317,16 @@ static grpc_error* fill_in_metadata(inproc_stream* s,
return error;
}
-static int init_stream(grpc_transport* gt, grpc_stream* gs,
- grpc_stream_refcount* refcount, const void* server_data,
- gpr_arena* arena) {
+int init_stream(grpc_transport* gt, grpc_stream* gs,
+ grpc_stream_refcount* refcount, const void* server_data,
+ gpr_arena* arena) {
INPROC_LOG(GPR_INFO, "init_stream %p %p %p", gt, gs, server_data);
inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
- inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
- s->arena = arena;
-
- s->refs = refcount;
- // Ref this stream right now
- ref_stream(s, "inproc_init_stream:init");
-
- grpc_metadata_batch_init(&s->to_read_initial_md);
- s->to_read_initial_md_flags = 0;
- s->to_read_initial_md_filled = false;
- grpc_metadata_batch_init(&s->to_read_trailing_md);
- s->to_read_trailing_md_filled = false;
- grpc_metadata_batch_init(&s->write_buffer_initial_md);
- s->write_buffer_initial_md_flags = 0;
- s->write_buffer_initial_md_filled = false;
- grpc_metadata_batch_init(&s->write_buffer_trailing_md);
- s->write_buffer_trailing_md_filled = false;
- s->ops_needed = false;
- s->op_closure_scheduled = false;
- GRPC_CLOSURE_INIT(&s->op_closure, op_state_machine, s,
- grpc_schedule_on_exec_ctx);
- s->t = t;
- s->closure_at_destroy = nullptr;
- s->other_side_closed = false;
-
- s->initial_md_sent = s->trailing_md_sent = s->initial_md_recvd =
- s->trailing_md_recvd = false;
-
- s->closed = false;
-
- s->cancel_self_error = GRPC_ERROR_NONE;
- s->cancel_other_error = GRPC_ERROR_NONE;
- s->write_buffer_cancel_error = GRPC_ERROR_NONE;
- s->deadline = GRPC_MILLIS_INF_FUTURE;
- s->write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
-
- s->stream_list_prev = nullptr;
- gpr_mu_lock(&t->mu->mu);
- s->listed = true;
- ref_stream(s, "inproc_init_stream:list");
- s->stream_list_next = t->stream_list;
- if (t->stream_list) {
- t->stream_list->stream_list_prev = s;
- }
- t->stream_list = s;
- gpr_mu_unlock(&t->mu->mu);
-
- if (!server_data) {
- ref_transport(t);
- inproc_transport* st = t->other_side;
- ref_transport(st);
- s->other_side = nullptr; // will get filled in soon
- // Pass the client-side stream address to the server-side for a ref
- ref_stream(s, "inproc_init_stream:clt"); // ref it now on behalf of server
- // side to avoid destruction
- INPROC_LOG(GPR_INFO, "calling accept stream cb %p %p", st->accept_stream_cb,
- st->accept_stream_data);
- (*st->accept_stream_cb)(st->accept_stream_data, &st->base, (void*)s);
- } else {
- // This is the server-side and is being called through accept_stream_cb
- inproc_stream* cs = (inproc_stream*)server_data;
- s->other_side = cs;
- // Ref the server-side stream on behalf of the client now
- ref_stream(s, "inproc_init_stream:srv");
-
- // Now we are about to affect the other side, so lock the transport
- // to make sure that it doesn't get destroyed
- gpr_mu_lock(&s->t->mu->mu);
- cs->other_side = s;
- // Now transfer from the other side's write_buffer if any to the to_read
- // buffer
- if (cs->write_buffer_initial_md_filled) {
- fill_in_metadata(s, &cs->write_buffer_initial_md,
- cs->write_buffer_initial_md_flags,
- &s->to_read_initial_md, &s->to_read_initial_md_flags,
- &s->to_read_initial_md_filled);
- s->deadline = GPR_MIN(s->deadline, cs->write_buffer_deadline);
- grpc_metadata_batch_clear(&cs->write_buffer_initial_md);
- cs->write_buffer_initial_md_filled = false;
- }
- if (cs->write_buffer_trailing_md_filled) {
- fill_in_metadata(s, &cs->write_buffer_trailing_md, 0,
- &s->to_read_trailing_md, nullptr,
- &s->to_read_trailing_md_filled);
- grpc_metadata_batch_clear(&cs->write_buffer_trailing_md);
- cs->write_buffer_trailing_md_filled = false;
- }
- if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) {
- s->cancel_other_error = cs->write_buffer_cancel_error;
- cs->write_buffer_cancel_error = GRPC_ERROR_NONE;
- }
-
- gpr_mu_unlock(&s->t->mu->mu);
- }
+ new (gs) inproc_stream(t, refcount, server_data, arena);
return 0; // return value is not important
}
-static void close_stream_locked(inproc_stream* s) {
+void close_stream_locked(inproc_stream* s) {
if (!s->closed) {
// Release the metadata that we would have written out
grpc_metadata_batch_destroy(&s->write_buffer_initial_md);
@@ -341,21 +344,21 @@ static void close_stream_locked(inproc_stream* s) {
n->stream_list_prev = p;
}
s->listed = false;
- unref_stream(s, "close_stream:list");
+ s->unref("close_stream:list");
}
s->closed = true;
- unref_stream(s, "close_stream:closing");
+ s->unref("close_stream:closing");
}
}
// This function means that we are done talking/listening to the other side
-static void close_other_side_locked(inproc_stream* s, const char* reason) {
+void close_other_side_locked(inproc_stream* s, const char* reason) {
if (s->other_side != nullptr) {
// First release the metadata that came from the other side's arena
grpc_metadata_batch_destroy(&s->to_read_initial_md);
grpc_metadata_batch_destroy(&s->to_read_trailing_md);
- unref_stream(s->other_side, reason);
+ s->other_side->unref(reason);
s->other_side_closed = true;
s->other_side = nullptr;
} else if (!s->other_side_closed) {
@@ -367,9 +370,9 @@ static void close_other_side_locked(inproc_stream* s, const char* reason) {
// this stream_op_batch is only one of the pending operations for this
// stream. This is called when one of the pending operations for the stream
// is done and about to be NULLed out
-static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
- grpc_transport_stream_op_batch* op,
- const char* msg) {
+void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
+ grpc_transport_stream_op_batch* op,
+ const char* msg) {
int is_sm = static_cast<int>(op == s->send_message_op);
int is_stm = static_cast<int>(op == s->send_trailing_md_op);
// TODO(vjpai): We should not consider the recv ops here, since they
@@ -386,8 +389,7 @@ static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
}
}
-static void maybe_schedule_op_closure_locked(inproc_stream* s,
- grpc_error* error) {
+void maybe_schedule_op_closure_locked(inproc_stream* s, grpc_error* error) {
if (s && s->ops_needed && !s->op_closure_scheduled) {
GRPC_CLOSURE_SCHED(&s->op_closure, GRPC_ERROR_REF(error));
s->op_closure_scheduled = true;
@@ -395,7 +397,7 @@ static void maybe_schedule_op_closure_locked(inproc_stream* s,
}
}
-static void fail_helper_locked(inproc_stream* s, grpc_error* error) {
+void fail_helper_locked(inproc_stream* s, grpc_error* error) {
INPROC_LOG(GPR_INFO, "op_state_machine %p fail_helper", s);
// If we're failing this side, we need to make sure that
// we also send or have already sent trailing metadata
@@ -525,8 +527,7 @@ static void fail_helper_locked(inproc_stream* s, grpc_error* error) {
// that the incoming byte stream's next() call will always return
// synchronously. That assumption is true today but may not always be
// true in the future.
-static void message_transfer_locked(inproc_stream* sender,
- inproc_stream* receiver) {
+void message_transfer_locked(inproc_stream* sender, inproc_stream* receiver) {
size_t remaining =
sender->send_message_op->payload->send_message.send_message->length();
if (receiver->recv_inited) {
@@ -572,7 +573,7 @@ static void message_transfer_locked(inproc_stream* sender,
sender->send_message_op = nullptr;
}
-static void op_state_machine(void* arg, grpc_error* error) {
+void op_state_machine(void* arg, grpc_error* error) {
// This function gets called when we have contents in the unprocessed reads
// Get what we want based on our ops wanted
// Schedule our appropriate closures
@@ -607,10 +608,8 @@ static void op_state_machine(void* arg, grpc_error* error) {
if (other->recv_message_op) {
message_transfer_locked(s, other);
maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE);
- } else if (!s->t->is_client &&
- (s->trailing_md_sent || other->recv_trailing_md_op)) {
- // A server send will never be matched if the client is waiting
- // for trailing metadata already
+ } else if (!s->t->is_client && s->trailing_md_sent) {
+ // A server send will never be matched if the server already sent status
s->send_message_op->payload->send_message.send_message.reset();
complete_if_batch_end_locked(
s, GRPC_ERROR_NONE, s->send_message_op,
@@ -621,11 +620,15 @@ static void op_state_machine(void* arg, grpc_error* error) {
// Pause a send trailing metadata if there is still an outstanding
// send message unless we know that the send message will never get
// matched to a receive. This happens on the client if the server has
- // already sent status.
+ // already sent status or on the server if the client has requested
+ // status
if (s->send_trailing_md_op &&
(!s->send_message_op ||
(s->t->is_client &&
- (s->trailing_md_recvd || s->to_read_trailing_md_filled)))) {
+ (s->trailing_md_recvd || s->to_read_trailing_md_filled)) ||
+ (!s->t->is_client && other &&
+ (other->trailing_md_recvd || other->to_read_trailing_md_filled ||
+ other->recv_trailing_md_op)))) {
grpc_metadata_batch* dest = (other == nullptr)
? &s->write_buffer_trailing_md
: &other->to_read_trailing_md;
@@ -723,16 +726,6 @@ static void op_state_machine(void* arg, grpc_error* error) {
maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE);
}
}
- if (s->recv_trailing_md_op && s->t->is_client && other &&
- other->send_message_op) {
- INPROC_LOG(GPR_INFO,
- "op_state_machine %p scheduling trailing-metadata-ready %p", s,
- GRPC_ERROR_NONE);
- GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->payload->recv_trailing_metadata
- .recv_trailing_metadata_ready,
- GRPC_ERROR_NONE);
- maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE);
- }
if (s->to_read_trailing_md_filled) {
if (s->trailing_md_recvd) {
new_err =
@@ -748,6 +741,7 @@ static void op_state_machine(void* arg, grpc_error* error) {
if (s->recv_message_op != nullptr) {
// This message needs to be wrapped up because it will never be
// satisfied
+ *s->recv_message_op->payload->recv_message.recv_message = nullptr;
INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s);
GRPC_CLOSURE_SCHED(
s->recv_message_op->payload->recv_message.recv_message_ready,
@@ -810,6 +804,7 @@ static void op_state_machine(void* arg, grpc_error* error) {
// No further message will come on this stream, so finish off the
// recv_message_op
INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s);
+ *s->recv_message_op->payload->recv_message.recv_message = nullptr;
GRPC_CLOSURE_SCHED(
s->recv_message_op->payload->recv_message.recv_message_ready,
GRPC_ERROR_NONE);
@@ -847,7 +842,7 @@ done:
GRPC_ERROR_UNREF(new_err);
}
-static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
+bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
bool ret = false; // was the cancel accepted
INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s, grpc_error_string(error));
if (s->cancel_self_error == GRPC_ERROR_NONE) {
@@ -900,10 +895,10 @@ static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
return ret;
}
-static void do_nothing(void* arg, grpc_error* error) {}
+void do_nothing(void* arg, grpc_error* error) {}
-static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
- grpc_transport_stream_op_batch* op) {
+void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
+ grpc_transport_stream_op_batch* op) {
INPROC_LOG(GPR_INFO, "perform_stream_op %p %p %p", gt, gs, op);
inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
gpr_mu* mu = &s->t->mu->mu; // save aside in case s gets closed
@@ -1012,18 +1007,18 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
}
// We want to initiate the closure if:
- // 1. We want to send a message and the other side wants to receive or end
+ // 1. We want to send a message and the other side wants to receive
// 2. We want to send trailing metadata and there isn't an unmatched send
+ // or the other side wants trailing metadata
// 3. We want initial metadata and the other side has sent it
// 4. We want to receive a message and there is a message ready
// 5. There is trailing metadata, even if nothing specifically wants
// that because that can shut down the receive message as well
- if ((op->send_message && other &&
- ((other->recv_message_op != nullptr) ||
- (other->recv_trailing_md_op != nullptr))) ||
- (op->send_trailing_metadata && !op->send_message) ||
+ if ((op->send_message && other && other->recv_message_op != nullptr) ||
+ (op->send_trailing_metadata &&
+ (!s->send_message_op || (other && other->recv_trailing_md_op))) ||
(op->recv_initial_metadata && s->to_read_initial_md_filled) ||
- (op->recv_message && other && (other->send_message_op != nullptr)) ||
+ (op->recv_message && other && other->send_message_op != nullptr) ||
(s->to_read_trailing_md_filled || s->trailing_md_recvd)) {
if (!s->op_closure_scheduled) {
GRPC_CLOSURE_SCHED(&s->op_closure, GRPC_ERROR_NONE);
@@ -1083,7 +1078,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
GRPC_ERROR_UNREF(error);
}
-static void close_transport_locked(inproc_transport* t) {
+void close_transport_locked(inproc_transport* t) {
INPROC_LOG(GPR_INFO, "close_transport %p %d", t, t->is_closed);
grpc_connectivity_state_set(
&t->connectivity, GRPC_CHANNEL_SHUTDOWN,
@@ -1103,7 +1098,7 @@ static void close_transport_locked(inproc_transport* t) {
}
}
-static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
+void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
INPROC_LOG(GPR_INFO, "perform_transport_op %p %p", t, op);
gpr_mu_lock(&t->mu->mu);
@@ -1136,39 +1131,64 @@ static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
gpr_mu_unlock(&t->mu->mu);
}
-static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
- grpc_closure* then_schedule_closure) {
+void destroy_stream(grpc_transport* gt, grpc_stream* gs,
+ grpc_closure* then_schedule_closure) {
INPROC_LOG(GPR_INFO, "destroy_stream %p %p", gs, then_schedule_closure);
inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
s->closure_at_destroy = then_schedule_closure;
- really_destroy_stream(s);
+ s->~inproc_stream();
}
-static void destroy_transport(grpc_transport* gt) {
+void destroy_transport(grpc_transport* gt) {
inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
INPROC_LOG(GPR_INFO, "destroy_transport %p", t);
gpr_mu_lock(&t->mu->mu);
close_transport_locked(t);
gpr_mu_unlock(&t->mu->mu);
- unref_transport(t->other_side);
- unref_transport(t);
+ t->other_side->unref();
+ t->unref();
}
/*******************************************************************************
* INTEGRATION GLUE
*/
-static void set_pollset(grpc_transport* gt, grpc_stream* gs,
- grpc_pollset* pollset) {
+void set_pollset(grpc_transport* gt, grpc_stream* gs, grpc_pollset* pollset) {
// Nothing to do here
}
-static void set_pollset_set(grpc_transport* gt, grpc_stream* gs,
- grpc_pollset_set* pollset_set) {
+void set_pollset_set(grpc_transport* gt, grpc_stream* gs,
+ grpc_pollset_set* pollset_set) {
// Nothing to do here
}
-static grpc_endpoint* get_endpoint(grpc_transport* t) { return nullptr; }
+grpc_endpoint* get_endpoint(grpc_transport* t) { return nullptr; }
+
+const grpc_transport_vtable inproc_vtable = {
+ sizeof(inproc_stream), "inproc", init_stream,
+ set_pollset, set_pollset_set, perform_stream_op,
+ perform_transport_op, destroy_stream, destroy_transport,
+ get_endpoint};
+
+/*******************************************************************************
+ * Main inproc transport functions
+ */
+void inproc_transports_create(grpc_transport** server_transport,
+ const grpc_channel_args* server_args,
+ grpc_transport** client_transport,
+ const grpc_channel_args* client_args) {
+ INPROC_LOG(GPR_INFO, "inproc_transports_create");
+ shared_mu* mu = new (gpr_malloc(sizeof(*mu))) shared_mu();
+ inproc_transport* st = new (gpr_malloc(sizeof(*st)))
+ inproc_transport(&inproc_vtable, mu, /*is_client=*/false);
+ inproc_transport* ct = new (gpr_malloc(sizeof(*ct)))
+ inproc_transport(&inproc_vtable, mu, /*is_client=*/true);
+ st->other_side = ct;
+ ct->other_side = st;
+ *server_transport = reinterpret_cast<grpc_transport*>(st);
+ *client_transport = reinterpret_cast<grpc_transport*>(ct);
+}
+} // namespace
/*******************************************************************************
* GLOBAL INIT AND DESTROY
@@ -1190,48 +1210,6 @@ void grpc_inproc_transport_init(void) {
g_fake_auth_value = grpc_slice_from_static_string("inproc-fail");
}
-static const grpc_transport_vtable inproc_vtable = {
- sizeof(inproc_stream), "inproc", init_stream,
- set_pollset, set_pollset_set, perform_stream_op,
- perform_transport_op, destroy_stream, destroy_transport,
- get_endpoint};
-
-/*******************************************************************************
- * Main inproc transport functions
- */
-static void inproc_transports_create(grpc_transport** server_transport,
- const grpc_channel_args* server_args,
- grpc_transport** client_transport,
- const grpc_channel_args* client_args) {
- INPROC_LOG(GPR_INFO, "inproc_transports_create");
- inproc_transport* st =
- static_cast<inproc_transport*>(gpr_zalloc(sizeof(*st)));
- inproc_transport* ct =
- static_cast<inproc_transport*>(gpr_zalloc(sizeof(*ct)));
- // Share one lock between both sides since both sides get affected
- st->mu = ct->mu = static_cast<shared_mu*>(gpr_malloc(sizeof(*st->mu)));
- gpr_mu_init(&st->mu->mu);
- gpr_ref_init(&st->mu->refs, 2);
- st->base.vtable = &inproc_vtable;
- ct->base.vtable = &inproc_vtable;
- // Start each side of transport with 2 refs since they each have a ref
- // to the other
- gpr_ref_init(&st->refs, 2);
- gpr_ref_init(&ct->refs, 2);
- st->is_client = false;
- ct->is_client = true;
- grpc_connectivity_state_init(&st->connectivity, GRPC_CHANNEL_READY,
- "inproc_server");
- grpc_connectivity_state_init(&ct->connectivity, GRPC_CHANNEL_READY,
- "inproc_client");
- st->other_side = ct;
- ct->other_side = st;
- st->stream_list = nullptr;
- ct->stream_list = nullptr;
- *server_transport = reinterpret_cast<grpc_transport*>(st);
- *client_transport = reinterpret_cast<grpc_transport*>(ct);
-}
-
grpc_channel* grpc_inproc_channel_create(grpc_server* server,
grpc_channel_args* args,
void* reserved) {
@@ -1258,7 +1236,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server,
// TODO(ncteisen): design and support channelz GetSocket for inproc.
grpc_server_setup_transport(server, server_transport, nullptr, server_args,
- 0);
+ nullptr);
grpc_channel* channel = grpc_channel_create(
"inproc", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport);
diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc
index 056fcd93de..df956c7176 100644
--- a/src/core/lib/channel/channel_stack.cc
+++ b/src/core/lib/channel/channel_stack.cc
@@ -157,7 +157,6 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
size_t count = channel_stack->count;
grpc_call_element* call_elems;
char* user_data;
- size_t i;
elem_args->call_stack->count = count;
GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
@@ -168,10 +167,14 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
/* init per-filter data */
grpc_error* first_error = GRPC_ERROR_NONE;
- for (i = 0; i < count; i++) {
+ for (size_t i = 0; i < count; i++) {
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
+ user_data +=
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
+ }
+ for (size_t i = 0; i < count; i++) {
grpc_error* error =
call_elems[i].filter->init_call_elem(&call_elems[i], elem_args);
if (error != GRPC_ERROR_NONE) {
@@ -181,8 +184,6 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
GRPC_ERROR_UNREF(error);
}
}
- user_data +=
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
}
return first_error;
}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 35c3fb01ea..0de8c67079 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -79,11 +79,11 @@ typedef struct {
} grpc_call_stats;
/** Information about the call upon completion. */
-typedef struct {
+struct grpc_call_final_info {
grpc_call_stats stats;
- grpc_status_code final_status;
- const char* error_string;
-} grpc_call_final_info;
+ grpc_status_code final_status = GRPC_STATUS_OK;
+ const char* error_string = nullptr;
+};
/* Channel filters specify:
1. the amount of memory needed in the channel & call (via the sizeof_XXX
diff --git a/src/core/lib/channel/channel_stack_builder.cc b/src/core/lib/channel/channel_stack_builder.cc
index df5a783631..8b3008f221 100644
--- a/src/core/lib/channel/channel_stack_builder.cc
+++ b/src/core/lib/channel/channel_stack_builder.cc
@@ -40,6 +40,7 @@ struct grpc_channel_stack_builder {
// various set/get-able parameters
grpc_channel_args* args;
grpc_transport* transport;
+ grpc_resource_user* resource_user;
char* target;
const char* name;
};
@@ -157,6 +158,11 @@ void grpc_channel_stack_builder_set_channel_arguments(
builder->args = grpc_channel_args_copy(args);
}
+const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
+ grpc_channel_stack_builder* builder) {
+ return builder->args;
+}
+
void grpc_channel_stack_builder_set_transport(
grpc_channel_stack_builder* builder, grpc_transport* transport) {
GPR_ASSERT(builder->transport == nullptr);
@@ -168,9 +174,15 @@ grpc_transport* grpc_channel_stack_builder_get_transport(
return builder->transport;
}
-const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
+void grpc_channel_stack_builder_set_resource_user(
+ grpc_channel_stack_builder* builder, grpc_resource_user* resource_user) {
+ GPR_ASSERT(builder->resource_user == nullptr);
+ builder->resource_user = resource_user;
+}
+
+grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
grpc_channel_stack_builder* builder) {
- return builder->args;
+ return builder->resource_user;
}
bool grpc_channel_stack_builder_append_filter(
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 9196de9378..89c30e0c5e 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -54,6 +54,14 @@ void grpc_channel_stack_builder_set_transport(
grpc_transport* grpc_channel_stack_builder_get_transport(
grpc_channel_stack_builder* builder);
+/// Attach \a resource_user to the builder (does not take ownership)
+void grpc_channel_stack_builder_set_resource_user(
+ grpc_channel_stack_builder* builder, grpc_resource_user* resource_user);
+
+/// Fetch attached resource user
+grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
+ grpc_channel_stack_builder* builder);
+
/// Set channel arguments: copies args
void grpc_channel_stack_builder_set_channel_arguments(
grpc_channel_stack_builder* builder, const grpc_channel_args* args);
diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc
index 33577d890a..0cb2890518 100644
--- a/src/core/lib/channel/channelz.cc
+++ b/src/core/lib/channel/channelz.cc
@@ -30,15 +30,18 @@
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/b64.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
namespace channelz {
@@ -204,22 +207,20 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id) {
grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json* json = top_level_json;
grpc_json* json_iterator = nullptr;
- ChildRefsList socket_refs;
- // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
- // reserved). However, we want to support requests coming in with
- // start_server_id=0, which signifies "give me everything."
- size_t start_idx = start_socket_id == 0 ? 0 : start_socket_id - 1;
- grpc_server_populate_server_sockets(server_, &socket_refs, start_idx);
+ ChildSocketsList socket_refs;
+ grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id);
if (!socket_refs.empty()) {
// create list of socket refs
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
for (size_t i = 0; i < socket_refs.size(); ++i) {
- json_iterator =
+ grpc_json* socket_ref_json =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
- grpc_json_add_number_string_child(json_iterator, nullptr, "socketId",
- socket_refs[i]);
+ json_iterator = grpc_json_add_number_string_child(
+ socket_ref_json, nullptr, "socketId", socket_refs[i]->uuid());
+ grpc_json_create_child(json_iterator, socket_ref_json, "name",
+ socket_refs[i]->remote(), GRPC_JSON_STRING, false);
}
}
// For now we do not have any pagination rules. In the future we could
@@ -277,7 +278,61 @@ grpc_json* ServerNode::RenderJson() {
return top_level_json;
}
-SocketNode::SocketNode() : BaseNode(EntityType::kSocket) {}
+static void PopulateSocketAddressJson(grpc_json* json, const char* name,
+ const char* addr_str) {
+ if (addr_str == nullptr) return;
+ grpc_json* json_iterator = nullptr;
+ json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ grpc_uri* uri = grpc_uri_parse(addr_str, true);
+ if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) ||
+ (strcmp(uri->scheme, "ipv6") == 0))) {
+ const char* host_port = uri->path;
+ if (*host_port == '/') ++host_port;
+ char* host = nullptr;
+ char* port = nullptr;
+ GPR_ASSERT(gpr_split_host_port(host_port, &host, &port));
+ int port_num = -1;
+ if (port != nullptr) {
+ port_num = atoi(port);
+ }
+ char* b64_host = grpc_base64_encode(host, strlen(host), false, false);
+ json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address",
+ nullptr, GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator = grpc_json_add_number_string_child(json, json_iterator,
+ "port", port_num);
+ json_iterator = grpc_json_create_child(json_iterator, json, "ip_address",
+ b64_host, GRPC_JSON_STRING, true);
+ gpr_free(host);
+ gpr_free(port);
+
+ } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) {
+ json_iterator = grpc_json_create_child(json_iterator, json, "uds_address",
+ nullptr, GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "filename",
+ gpr_strdup(uri->path), GRPC_JSON_STRING, true);
+ } else {
+ json_iterator = grpc_json_create_child(json_iterator, json, "other_address",
+ nullptr, GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator = grpc_json_create_child(json_iterator, json, "name",
+ addr_str, GRPC_JSON_STRING, false);
+ }
+ grpc_uri_destroy(uri);
+}
+
+SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote)
+ : BaseNode(EntityType::kSocket),
+ local_(std::move(local)),
+ remote_(std::move(remote)) {}
void SocketNode::RecordStreamStartedFromLocal() {
gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
@@ -315,6 +370,9 @@ grpc_json* SocketNode::RenderJson() {
json_iterator = nullptr;
json_iterator = grpc_json_add_number_string_child(json, json_iterator,
"socketId", uuid());
+ json = top_level_json;
+ PopulateSocketAddressJson(json, "remote", remote_.get());
+ PopulateSocketAddressJson(json, "local", local_.get());
// reset json iterators to top level object
json = top_level_json;
json_iterator = nullptr;
@@ -374,7 +432,8 @@ grpc_json* SocketNode::RenderJson() {
return top_level_json;
}
-ListenSocketNode::ListenSocketNode() : BaseNode(EntityType::kSocket) {}
+ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr)
+ : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {}
grpc_json* ListenSocketNode::RenderJson() {
// We need to track these three json objects to build our object
@@ -388,6 +447,9 @@ grpc_json* ListenSocketNode::RenderJson() {
json_iterator = nullptr;
json_iterator = grpc_json_add_number_string_child(json, json_iterator,
"socketId", uuid());
+ json = top_level_json;
+ PopulateSocketAddressJson(json, "local", local_addr_.get());
+
return top_level_json;
}
diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h
index 88551befc8..96a4333083 100644
--- a/src/core/lib/channel/channelz.h
+++ b/src/core/lib/channel/channelz.h
@@ -59,6 +59,9 @@ namespace channelz {
// add human readable names as in the channelz.proto
typedef InlinedVector<intptr_t, 10> ChildRefsList;
+class SocketNode;
+typedef InlinedVector<SocketNode*, 10> ChildSocketsList;
+
namespace testing {
class CallCountingHelperPeer;
class ChannelNodePeer;
@@ -232,7 +235,7 @@ class ServerNode : public BaseNode {
// Handles channelz bookkeeping for sockets
class SocketNode : public BaseNode {
public:
- SocketNode();
+ SocketNode(UniquePtr<char> local, UniquePtr<char> remote);
~SocketNode() override {}
grpc_json* RenderJson() override;
@@ -251,6 +254,8 @@ class SocketNode : public BaseNode {
gpr_atm_no_barrier_fetch_add(&keepalives_sent_, static_cast<gpr_atm>(1));
}
+ const char* remote() { return remote_.get(); }
+
private:
gpr_atm streams_started_ = 0;
gpr_atm streams_succeeded_ = 0;
@@ -262,16 +267,21 @@ class SocketNode : public BaseNode {
gpr_atm last_remote_stream_created_millis_ = 0;
gpr_atm last_message_sent_millis_ = 0;
gpr_atm last_message_received_millis_ = 0;
- UniquePtr<char> peer_string_;
+ UniquePtr<char> local_;
+ UniquePtr<char> remote_;
};
// Handles channelz bookkeeping for listen sockets
class ListenSocketNode : public BaseNode {
public:
- ListenSocketNode();
+ // ListenSocketNode takes ownership of host.
+ explicit ListenSocketNode(UniquePtr<char> local_addr);
~ListenSocketNode() override {}
grpc_json* RenderJson() override;
+
+ private:
+ UniquePtr<char> local_addr_;
};
// Creation functions
diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc
index 1fe2fad3e1..bc23b90a66 100644
--- a/src/core/lib/channel/channelz_registry.cc
+++ b/src/core/lib/channel/channelz_registry.cc
@@ -210,6 +210,17 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
return json_str;
}
+void ChannelzRegistry::InternalLogAllEntities() {
+ MutexLock lock(&mu_);
+ for (size_t i = 0; i < entities_.size(); ++i) {
+ if (entities_[i] != nullptr) {
+ char* json = entities_[i]->RenderJsonString();
+ gpr_log(GPR_INFO, "%s", json);
+ gpr_free(json);
+ }
+ }
+}
+
} // namespace channelz
} // namespace grpc_core
@@ -222,6 +233,24 @@ char* grpc_channelz_get_servers(intptr_t start_server_id) {
return grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id);
}
+char* grpc_channelz_get_server(intptr_t server_id) {
+ grpc_core::channelz::BaseNode* server_node =
+ grpc_core::channelz::ChannelzRegistry::Get(server_id);
+ if (server_node == nullptr ||
+ server_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kServer) {
+ return nullptr;
+ }
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* channel_json = server_node->RenderJson();
+ channel_json->key = "server";
+ grpc_json_link_child(json, channel_json, nullptr);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
+
char* grpc_channelz_get_server_sockets(intptr_t server_id,
intptr_t start_socket_id) {
grpc_core::channelz::BaseNode* base_node =
diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h
index 326f0201c7..73b330785d 100644
--- a/src/core/lib/channel/channelz_registry.h
+++ b/src/core/lib/channel/channelz_registry.h
@@ -62,6 +62,10 @@ class ChannelzRegistry {
return Default()->InternalGetServers(start_server_id);
}
+ // Test only helper function to dump the JSON representation to std out.
+ // This can aid in debugging channelz code.
+ static void LogAllEntities() { Default()->InternalLogAllEntities(); }
+
private:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
@@ -96,6 +100,8 @@ class ChannelzRegistry {
// Else, will return idx of the first uuid higher than the target.
int FindByUuidLocked(intptr_t uuid, bool direct_hit_needed);
+ void InternalLogAllEntities();
+
// protects members
gpr_mu mu_;
InlinedVector<BaseNode*, 20> entities_;
diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h
index 5daf48a9a9..763e4ffc9f 100644
--- a/src/core/lib/channel/context.h
+++ b/src/core/lib/channel/context.h
@@ -41,9 +41,9 @@ typedef enum {
GRPC_CONTEXT_COUNT
} grpc_context_index;
-typedef struct {
- void* value;
- void (*destroy)(void*);
-} grpc_call_context_element;
+struct grpc_call_context_element {
+ void* value = nullptr;
+ void (*destroy)(void*) = nullptr;
+};
#endif /* GRPC_CORE_LIB_CHANNEL_CONTEXT_H */
diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc
index 01c1e867d9..cafdb15c69 100644
--- a/src/core/lib/debug/trace.cc
+++ b/src/core/lib/debug/trace.cc
@@ -21,6 +21,7 @@
#include "src/core/lib/debug/trace.h"
#include <string.h>
+#include <type_traits>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
@@ -79,6 +80,8 @@ void TraceFlagList::LogAllTracers() {
// Flags register themselves on the list during construction
TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
+ static_assert(std::is_trivially_destructible<TraceFlag>::value,
+ "TraceFlag needs to be trivially destructible.");
set_enabled(default_enabled);
TraceFlagList::Add(this);
}
diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h
index fe6301a3fc..4623494520 100644
--- a/src/core/lib/debug/trace.h
+++ b/src/core/lib/debug/trace.h
@@ -53,7 +53,8 @@ void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag);
class TraceFlag {
public:
TraceFlag(bool default_enabled, const char* name);
- ~TraceFlag() {}
+ // This needs to be trivially destructible as it is used as global variable.
+ ~TraceFlag() = default;
const char* name() const { return name_; }
@@ -102,8 +103,9 @@ typedef TraceFlag DebugOnlyTraceFlag;
#else
class DebugOnlyTraceFlag {
public:
- DebugOnlyTraceFlag(bool default_enabled, const char* name) {}
- bool enabled() { return false; }
+ constexpr DebugOnlyTraceFlag(bool default_enabled, const char* name) {}
+ constexpr bool enabled() const { return false; }
+ constexpr const char* name() const { return "DebugOnlyTraceFlag"; }
private:
void set_enabled(bool enabled) {}
diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc
index 77f9357146..836a7ca793 100644
--- a/src/core/lib/gpr/arena.cc
+++ b/src/core/lib/gpr/arena.cc
@@ -21,6 +21,7 @@
#include "src/core/lib/gpr/arena.h"
#include <string.h>
+#include <new>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
@@ -28,34 +29,79 @@
#include <grpc/support/sync.h>
#include "src/core/lib/gpr/alloc.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace {
+enum init_strategy {
+ NO_INIT, // Do not initialize the arena blocks.
+ ZERO_INIT, // Initialize arena blocks with 0.
+ NON_ZERO_INIT, // Initialize arena blocks with a non-zero value.
+};
+
+gpr_once g_init_strategy_once = GPR_ONCE_INIT;
+init_strategy g_init_strategy = NO_INIT;
+} // namespace
+
+static void set_strategy_from_env() {
+ char* str = gpr_getenv("GRPC_ARENA_INIT_STRATEGY");
+ if (str == nullptr) {
+ g_init_strategy = NO_INIT;
+ } else if (strcmp(str, "zero_init") == 0) {
+ g_init_strategy = ZERO_INIT;
+ } else if (strcmp(str, "non_zero_init") == 0) {
+ g_init_strategy = NON_ZERO_INIT;
+ } else {
+ g_init_strategy = NO_INIT;
+ }
+ gpr_free(str);
+}
+
+static void* gpr_arena_alloc_maybe_init(size_t size) {
+ void* mem = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT);
+ gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
+ if (GPR_UNLIKELY(g_init_strategy != NO_INIT)) {
+ if (g_init_strategy == ZERO_INIT) {
+ memset(mem, 0, size);
+ } else { // NON_ZERO_INIT.
+ memset(mem, 0xFE, size);
+ }
+ }
+ return mem;
+}
+
+void gpr_arena_init() {
+ gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
+}
// Uncomment this to use a simple arena that simply allocates the
// requested amount of memory for each call to gpr_arena_alloc(). This
// effectively eliminates the efficiency gain of using an arena, but it
// may be useful for debugging purposes.
//#define SIMPLE_ARENA_FOR_DEBUGGING
-
#ifdef SIMPLE_ARENA_FOR_DEBUGGING
struct gpr_arena {
+ gpr_arena() { gpr_mu_init(&mu); }
+ ~gpr_arena() {
+ gpr_mu_destroy(&mu);
+ for (size_t i = 0; i < num_ptrs; ++i) {
+ gpr_free_aligned(ptrs[i]);
+ }
+ gpr_free(ptrs);
+ }
+
gpr_mu mu;
- void** ptrs;
- size_t num_ptrs;
+ void** ptrs = nullptr;
+ size_t num_ptrs = 0;
};
gpr_arena* gpr_arena_create(size_t ignored_initial_size) {
- gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena));
- gpr_mu_init(&arena->mu);
- return arena;
+ return grpc_core::New<gpr_arena>();
}
size_t gpr_arena_destroy(gpr_arena* arena) {
- gpr_mu_destroy(&arena->mu);
- for (size_t i = 0; i < arena->num_ptrs; ++i) {
- gpr_free(arena->ptrs[i]);
- }
- gpr_free(arena->ptrs);
- gpr_free(arena);
+ grpc_core::Delete(arena);
return 1; // Value doesn't matter, since it won't be used.
}
@@ -63,7 +109,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
gpr_mu_lock(&arena->mu);
arena->ptrs =
(void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1));
- void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size);
+ void* retval = arena->ptrs[arena->num_ptrs++] =
+ gpr_arena_alloc_maybe_init(size);
gpr_mu_unlock(&arena->mu);
return retval;
}
@@ -77,45 +124,45 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
// would allow us to use the alignment actually needed by the caller.
typedef struct zone {
- zone* next;
+ zone* next = nullptr;
} zone;
struct gpr_arena {
+ gpr_arena(size_t initial_size)
+ : initial_zone_size(initial_size), last_zone(&initial_zone) {
+ gpr_mu_init(&arena_growth_mutex);
+ }
+ ~gpr_arena() {
+ gpr_mu_destroy(&arena_growth_mutex);
+ zone* z = initial_zone.next;
+ while (z) {
+ zone* next_z = z->next;
+ z->~zone();
+ gpr_free_aligned(z);
+ z = next_z;
+ }
+ }
+
// Keep track of the total used size. We use this in our call sizing
// historesis.
- gpr_atm total_used;
+ gpr_atm total_used = 0;
size_t initial_zone_size;
zone initial_zone;
zone* last_zone;
gpr_mu arena_growth_mutex;
};
-static void* zalloc_aligned(size_t size) {
- void* ptr = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT);
- memset(ptr, 0, size);
- return ptr;
-}
-
gpr_arena* gpr_arena_create(size_t initial_size) {
initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
- gpr_arena* a = static_cast<gpr_arena*>(zalloc_aligned(
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size));
- a->initial_zone_size = initial_size;
- a->last_zone = &a->initial_zone;
- gpr_mu_init(&a->arena_growth_mutex);
- return a;
+ return new (gpr_arena_alloc_maybe_init(
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size))
+ gpr_arena(initial_size);
}
size_t gpr_arena_destroy(gpr_arena* arena) {
- gpr_mu_destroy(&arena->arena_growth_mutex);
- gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used);
- zone* z = arena->initial_zone.next;
+ const gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used);
+ arena->~gpr_arena();
gpr_free_aligned(arena);
- while (z) {
- zone* next_z = z->next;
- gpr_free_aligned(z);
- z = next_z;
- }
return static_cast<size_t>(size);
}
@@ -132,8 +179,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
// sizing historesis (that is, most calls should have a large enough initial
// zone and will not need to grow the arena).
gpr_mu_lock(&arena->arena_growth_mutex);
- zone* z = static_cast<zone*>(
- zalloc_aligned(GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size));
+ zone* z = new (gpr_arena_alloc_maybe_init(
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)) zone();
arena->last_zone->next = z;
arena->last_zone = z;
gpr_mu_unlock(&arena->arena_growth_mutex);
diff --git a/src/core/lib/gpr/arena.h b/src/core/lib/gpr/arena.h
index 6d2a073dd5..069892b228 100644
--- a/src/core/lib/gpr/arena.h
+++ b/src/core/lib/gpr/arena.h
@@ -37,5 +37,7 @@ gpr_arena* gpr_arena_create(size_t initial_size);
void* gpr_arena_alloc(gpr_arena* arena, size_t size);
// Destroy an arena, returning the total number of bytes allocated
size_t gpr_arena_destroy(gpr_arena* arena);
+// Initializes the Arena component.
+void gpr_arena_init();
#endif /* GRPC_CORE_LIB_GPR_ARENA_H */
diff --git a/src/core/lib/gprpp/inlined_vector.h b/src/core/lib/gprpp/inlined_vector.h
index 65c2b9634f..66dc751a56 100644
--- a/src/core/lib/gprpp/inlined_vector.h
+++ b/src/core/lib/gprpp/inlined_vector.h
@@ -100,10 +100,7 @@ class InlinedVector {
void reserve(size_t capacity) {
if (capacity > capacity_) {
T* new_dynamic = static_cast<T*>(gpr_malloc(sizeof(T) * capacity));
- for (size_t i = 0; i < size_; ++i) {
- new (&new_dynamic[i]) T(std::move(data()[i]));
- data()[i].~T();
- }
+ move_elements(data(), new_dynamic, size_);
gpr_free(dynamic_);
dynamic_ = new_dynamic;
capacity_ = capacity;
@@ -131,13 +128,25 @@ class InlinedVector {
size_--;
}
+ size_t size() const { return size_; }
+ bool empty() const { return size_ == 0; }
+
+ size_t capacity() const { return capacity_; }
+
+ void clear() {
+ destroy_elements();
+ init_data();
+ }
+
+ private:
void copy_from(const InlinedVector& v) {
- // if v is allocated, copy over the buffer.
+ // if v is allocated, make sure we have enough capacity.
if (v.dynamic_ != nullptr) {
reserve(v.capacity_);
- memcpy(dynamic_, v.dynamic_, v.size_ * sizeof(T));
- } else {
- memcpy(inline_, v.inline_, v.size_ * sizeof(T));
+ }
+ // copy over elements
+ for (size_t i = 0; i < v.size_; ++i) {
+ new (&(data()[i])) T(v[i]);
}
// copy over metadata
size_ = v.size_;
@@ -145,11 +154,12 @@ class InlinedVector {
}
void move_from(InlinedVector& v) {
- // if v is allocated, then we steal its buffer, else we copy it.
+ // if v is allocated, then we steal its dynamic array; otherwise, we
+ // move the elements individually.
if (v.dynamic_ != nullptr) {
dynamic_ = v.dynamic_;
} else {
- memcpy(inline_, v.inline_, v.size_ * sizeof(T));
+ move_elements(v.data(), data(), v.size_);
}
// copy over metadata
size_ = v.size_;
@@ -158,17 +168,13 @@ class InlinedVector {
v.init_data();
}
- size_t size() const { return size_; }
- bool empty() const { return size_ == 0; }
-
- size_t capacity() const { return capacity_; }
-
- void clear() {
- destroy_elements();
- init_data();
+ static void move_elements(T* src, T* dst, size_t num_elements) {
+ for (size_t i = 0; i < num_elements; ++i) {
+ new (&dst[i]) T(std::move(src[i]));
+ src[i].~T();
+ }
}
- private:
void init_data() {
dynamic_ = nullptr;
size_ = 0;
diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h
index 3123e3f5a3..9053c60111 100644
--- a/src/core/lib/gprpp/orphanable.h
+++ b/src/core/lib/gprpp/orphanable.h
@@ -31,6 +31,7 @@
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
@@ -89,107 +90,42 @@ class InternallyRefCounted : public Orphanable {
template <typename T>
friend class RefCountedPtr;
- InternallyRefCounted() { gpr_ref_init(&refs_, 1); }
- virtual ~InternallyRefCounted() {}
+ // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
+ // Note: RefCount tracing is only enabled on debug builds, even when a
+ // TraceFlag is used.
+ template <typename TraceFlagT = TraceFlag>
+ explicit InternallyRefCounted(TraceFlagT* trace_flag = nullptr)
+ : refs_(1, trace_flag) {}
+ virtual ~InternallyRefCounted() = default;
RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
IncrementRefCount();
return RefCountedPtr<Child>(static_cast<Child*>(this));
}
-
- void Unref() {
- if (gpr_unref(&refs_)) {
- Delete(static_cast<Child*>(this));
- }
- }
-
- private:
- void IncrementRefCount() { gpr_ref(&refs_); }
-
- gpr_refcount refs_;
-};
-
-// An alternative version of the InternallyRefCounted base class that
-// supports tracing. This is intended to be used in cases where the
-// object will be handled both by idiomatic C++ code using smart
-// pointers and legacy code that is manually calling Ref() and Unref().
-// Once all of our code is converted to idiomatic C++, we may be able to
-// eliminate this class.
-template <typename Child>
-class InternallyRefCountedWithTracing : public Orphanable {
- public:
- // Not copyable nor movable.
- InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) =
- delete;
- InternallyRefCountedWithTracing& operator=(
- const InternallyRefCountedWithTracing&) = delete;
-
- GRPC_ABSTRACT_BASE_CLASS
-
- protected:
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
-
- // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
- template <typename T>
- friend class RefCountedPtr;
-
- InternallyRefCountedWithTracing()
- : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
-
- explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag)
- : trace_flag_(trace_flag) {
- gpr_ref_init(&refs_, 1);
- }
-
-#ifdef NDEBUG
- explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
- : InternallyRefCountedWithTracing() {}
-#endif
-
- virtual ~InternallyRefCountedWithTracing() {}
-
- RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
- IncrementRefCount();
- return RefCountedPtr<Child>(static_cast<Child*>(this));
- }
-
RefCountedPtr<Child> Ref(const DebugLocation& location,
const char* reason) GRPC_MUST_USE_RESULT {
- if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
- gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
- gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
- trace_flag_->name(), this, location.file(), location.line(),
- old_refs, old_refs + 1, reason);
- }
- return Ref();
+ IncrementRefCount(location, reason);
+ return RefCountedPtr<Child>(static_cast<Child*>(this));
}
- // TODO(roth): Once all of our code is converted to C++ and can use
- // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
- // private, since they will only be used by RefCountedPtr<>, which is a
- // friend of this class.
-
void Unref() {
- if (gpr_unref(&refs_)) {
+ if (refs_.Unref()) {
Delete(static_cast<Child*>(this));
}
}
-
void Unref(const DebugLocation& location, const char* reason) {
- if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
- gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
- gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
- trace_flag_->name(), this, location.file(), location.line(),
- old_refs, old_refs - 1, reason);
+ if (refs_.Unref(location, reason)) {
+ Delete(static_cast<Child*>(this));
}
- Unref();
}
private:
- void IncrementRefCount() { gpr_ref(&refs_); }
+ void IncrementRefCount() { refs_.Ref(); }
+ void IncrementRefCount(const DebugLocation& location, const char* reason) {
+ refs_.Ref(location, reason);
+ }
- TraceFlag* trace_flag_ = nullptr;
- gpr_refcount refs_;
+ grpc_core::RefCount refs_;
};
} // namespace grpc_core
diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h
index 03c293f6ed..fa97ffcfed 100644
--- a/src/core/lib/gprpp/ref_counted.h
+++ b/src/core/lib/gprpp/ref_counted.h
@@ -21,9 +21,12 @@
#include <grpc/support/port_platform.h>
+#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include <atomic>
+#include <cassert>
#include <cinttypes>
#include "src/core/lib/debug/trace.h"
@@ -34,61 +37,150 @@
namespace grpc_core {
-// A base class for reference-counted objects.
-// New objects should be created via New() and start with a refcount of 1.
-// When the refcount reaches 0, the object will be deleted via Delete().
-//
-// This will commonly be used by CRTP (curiously-recurring template pattern)
-// e.g., class MyClass : public RefCounted<MyClass>
-template <typename Child>
-class RefCounted {
+// PolymorphicRefCount enforces polymorphic destruction of RefCounted.
+class PolymorphicRefCount {
public:
- RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
- IncrementRefCount();
- return RefCountedPtr<Child>(static_cast<Child*>(this));
- }
+ GRPC_ABSTRACT_BASE_CLASS
- // TODO(roth): Once all of our code is converted to C++ and can use
- // RefCountedPtr<> instead of manual ref-counting, make this method
- // private, since it will only be used by RefCountedPtr<>, which is a
- // friend of this class.
- void Unref() {
- if (gpr_unref(&refs_)) {
- Delete(static_cast<Child*>(this));
- }
- }
+ protected:
+ GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- // Not copyable nor movable.
- RefCounted(const RefCounted&) = delete;
- RefCounted& operator=(const RefCounted&) = delete;
+ virtual ~PolymorphicRefCount() = default;
+};
+// NonPolymorphicRefCount does not enforce polymorphic destruction of
+// RefCounted. Please refer to grpc_core::RefCounted for more details, and
+// when in doubt use PolymorphicRefCount.
+class NonPolymorphicRefCount {
+ public:
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- RefCounted() { gpr_ref_init(&refs_, 1); }
+ ~NonPolymorphicRefCount() = default;
+};
- virtual ~RefCounted() {}
+// RefCount is a simple atomic ref-count.
+//
+// This is a C++ implementation of gpr_refcount, with inline functions. Due to
+// inline functions, this class is significantly more efficient than
+// gpr_refcount and should be preferred over gpr_refcount whenever possible.
+//
+// TODO(soheil): Remove gpr_refcount after submitting the GRFC and the paragraph
+// above.
+class RefCount {
+ public:
+ using Value = intptr_t;
+
+ // `init` is the initial refcount stored in this object.
+ //
+ // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
+ // Note: RefCount tracing is only enabled on debug builds, even when a
+ // TraceFlag is used.
+ template <typename TraceFlagT = TraceFlag>
+ constexpr explicit RefCount(Value init = 1, TraceFlagT* trace_flag = nullptr)
+ :
+#ifndef NDEBUG
+ trace_flag_(trace_flag),
+#endif
+ value_(init) {
+ }
- private:
- // Allow RefCountedPtr<> to access IncrementRefCount().
- template <typename T>
- friend class RefCountedPtr;
+ // Increases the ref-count by `n`.
+ void Ref(Value n = 1) {
+ GPR_ATM_INC_ADD_THEN(value_.fetch_add(n, std::memory_order_relaxed));
+ }
+ void Ref(const DebugLocation& location, const char* reason, Value n = 1) {
+#ifndef NDEBUG
+ if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
+ const RefCount::Value old_refs = get();
+ gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
+ trace_flag_->name(), this, location.file(), location.line(),
+ old_refs, old_refs + n, reason);
+ }
+#endif
+ Ref(n);
+ }
+
+ // Similar to Ref() with an assert on the ref-count being non-zero.
+ void RefNonZero() {
+#ifndef NDEBUG
+ const Value prior =
+ GPR_ATM_INC_ADD_THEN(value_.fetch_add(1, std::memory_order_relaxed));
+ assert(prior > 0);
+#else
+ Ref();
+#endif
+ }
+ void RefNonZero(const DebugLocation& location, const char* reason) {
+#ifndef NDEBUG
+ if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
+ const RefCount::Value old_refs = get();
+ gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
+ trace_flag_->name(), this, location.file(), location.line(),
+ old_refs, old_refs + 1, reason);
+ }
+#endif
+ RefNonZero();
+ }
- void IncrementRefCount() { gpr_ref(&refs_); }
+ // Decrements the ref-count and returns true if the ref-count reaches 0.
+ bool Unref() {
+ const Value prior =
+ GPR_ATM_INC_ADD_THEN(value_.fetch_sub(1, std::memory_order_acq_rel));
+ GPR_DEBUG_ASSERT(prior > 0);
+ return prior == 1;
+ }
+ bool Unref(const DebugLocation& location, const char* reason) {
+#ifndef NDEBUG
+ if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
+ const RefCount::Value old_refs = get();
+ gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
+ trace_flag_->name(), this, location.file(), location.line(),
+ old_refs, old_refs - 1, reason);
+ }
+#endif
+ return Unref();
+ }
- gpr_refcount refs_;
+ private:
+ Value get() const { return value_.load(std::memory_order_relaxed); }
+
+#ifndef NDEBUG
+ TraceFlag* trace_flag_;
+#endif
+ std::atomic<Value> value_;
};
-// An alternative version of the RefCounted base class that
-// supports tracing. This is intended to be used in cases where the
-// object will be handled both by idiomatic C++ code using smart
-// pointers and legacy code that is manually calling Ref() and Unref().
-// Once all of our code is converted to idiomatic C++, we may be able to
-// eliminate this class.
-template <typename Child>
-class RefCountedWithTracing {
+// A base class for reference-counted objects.
+// New objects should be created via New() and start with a refcount of 1.
+// When the refcount reaches 0, the object will be deleted via Delete().
+//
+// This will commonly be used by CRTP (curiously-recurring template pattern)
+// e.g., class MyClass : public RefCounted<MyClass>
+//
+// Use PolymorphicRefCount and NonPolymorphicRefCount to select between
+// different implementations of RefCounted.
+//
+// Note that NonPolymorphicRefCount does not support polymorphic destruction.
+// So, use NonPolymorphicRefCount only when both of the following conditions
+// are guaranteed to hold:
+// (a) Child is a concrete leaf class in RefCounted<Child>, and
+// (b) you are gauranteed to call Unref only on concrete leaf classes and not
+// their parents.
+//
+// The following example is illegal, because calling Unref() will not call
+// the dtor of Child.
+//
+// class Parent : public RefCounted<Parent, NonPolymorphicRefCount> {}
+// class Child : public Parent {}
+//
+// Child* ch;
+// ch->Unref();
+//
+template <typename Child, typename Impl = PolymorphicRefCount>
+class RefCounted : public Impl {
public:
RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
IncrementRefCount();
@@ -97,69 +189,55 @@ class RefCountedWithTracing {
RefCountedPtr<Child> Ref(const DebugLocation& location,
const char* reason) GRPC_MUST_USE_RESULT {
- if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
- gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
- gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
- trace_flag_->name(), this, location.file(), location.line(),
- old_refs, old_refs + 1, reason);
- }
- return Ref();
+ IncrementRefCount(location, reason);
+ return RefCountedPtr<Child>(static_cast<Child*>(this));
}
// TODO(roth): Once all of our code is converted to C++ and can use
- // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
- // private, since they will only be used by RefCountedPtr<>, which is a
+ // RefCountedPtr<> instead of manual ref-counting, make this method
+ // private, since it will only be used by RefCountedPtr<>, which is a
// friend of this class.
-
void Unref() {
- if (gpr_unref(&refs_)) {
+ if (refs_.Unref()) {
Delete(static_cast<Child*>(this));
}
}
-
void Unref(const DebugLocation& location, const char* reason) {
- if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
- gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
- gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
- trace_flag_->name(), this, location.file(), location.line(),
- old_refs, old_refs - 1, reason);
+ if (refs_.Unref(location, reason)) {
+ Delete(static_cast<Child*>(this));
}
- Unref();
}
// Not copyable nor movable.
- RefCountedWithTracing(const RefCountedWithTracing&) = delete;
- RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete;
+ RefCounted(const RefCounted&) = delete;
+ RefCounted& operator=(const RefCounted&) = delete;
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- RefCountedWithTracing()
- : RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
-
- explicit RefCountedWithTracing(TraceFlag* trace_flag)
- : trace_flag_(trace_flag) {
- gpr_ref_init(&refs_, 1);
- }
-
-#ifdef NDEBUG
- explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
- : RefCountedWithTracing() {}
-#endif
+ // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
+ // Note: RefCount tracing is only enabled on debug builds, even when a
+ // TraceFlag is used.
+ template <typename TraceFlagT = TraceFlag>
+ explicit RefCounted(TraceFlagT* trace_flag = nullptr)
+ : refs_(1, trace_flag) {}
- virtual ~RefCountedWithTracing() {}
+ // Note: Depending on the Impl used, this dtor can be implicitly virtual.
+ ~RefCounted() = default;
private:
// Allow RefCountedPtr<> to access IncrementRefCount().
template <typename T>
friend class RefCountedPtr;
- void IncrementRefCount() { gpr_ref(&refs_); }
+ void IncrementRefCount() { refs_.Ref(); }
+ void IncrementRefCount(const DebugLocation& location, const char* reason) {
+ refs_.Ref(location, reason);
+ }
- TraceFlag* trace_flag_ = nullptr;
- gpr_refcount refs_;
+ RefCount refs_;
};
} // namespace grpc_core
diff --git a/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h
index c2dfbdd90f..1ed5d584c7 100644
--- a/src/core/lib/gprpp/ref_counted_ptr.h
+++ b/src/core/lib/gprpp/ref_counted_ptr.h
@@ -21,8 +21,10 @@
#include <grpc/support/port_platform.h>
+#include <type_traits>
#include <utility>
+#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/memory.h"
namespace grpc_core {
@@ -54,15 +56,13 @@ class RefCountedPtr {
// Move assignment.
RefCountedPtr& operator=(RefCountedPtr&& other) {
- if (value_ != nullptr) value_->Unref();
- value_ = other.value_;
+ reset(other.value_);
other.value_ = nullptr;
return *this;
}
template <typename Y>
RefCountedPtr& operator=(RefCountedPtr<Y>&& other) {
- if (value_ != nullptr) value_->Unref();
- value_ = other.value_;
+ reset(other.value_);
other.value_ = nullptr;
return *this;
}
@@ -74,6 +74,8 @@ class RefCountedPtr {
}
template <typename Y>
RefCountedPtr(const RefCountedPtr<Y>& other) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
if (other.value_ != nullptr) other.value_->IncrementRefCount();
value_ = other.value_;
}
@@ -83,17 +85,17 @@ class RefCountedPtr {
// Note: Order of reffing and unreffing is important here in case value_
// and other.value_ are the same object.
if (other.value_ != nullptr) other.value_->IncrementRefCount();
- if (value_ != nullptr) value_->Unref();
- value_ = other.value_;
+ reset(other.value_);
return *this;
}
template <typename Y>
RefCountedPtr& operator=(const RefCountedPtr<Y>& other) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
// Note: Order of reffing and unreffing is important here in case value_
// and other.value_ are the same object.
if (other.value_ != nullptr) other.value_->IncrementRefCount();
- if (value_ != nullptr) value_->Unref();
- value_ = other.value_;
+ reset(other.value_);
return *this;
}
@@ -102,15 +104,29 @@ class RefCountedPtr {
}
// If value is non-null, we take ownership of a ref to it.
- template <typename Y>
- void reset(Y* value) {
+ void reset(T* value = nullptr) {
if (value_ != nullptr) value_->Unref();
value_ = value;
}
-
- void reset() {
+ void reset(const DebugLocation& location, const char* reason,
+ T* value = nullptr) {
+ if (value_ != nullptr) value_->Unref(location, reason);
+ value_ = value;
+ }
+ template <typename Y>
+ void reset(Y* value = nullptr) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
if (value_ != nullptr) value_->Unref();
- value_ = nullptr;
+ value_ = value;
+ }
+ template <typename Y>
+ void reset(const DebugLocation& location, const char* reason,
+ Y* value = nullptr) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
+ if (value_ != nullptr) value_->Unref(location, reason);
+ value_ = value;
}
// TODO(roth): This method exists solely as a transition mechanism to allow
diff --git a/src/core/lib/iomgr/buffer_list.cc b/src/core/lib/iomgr/buffer_list.cc
index 6ada23db1c..ace17a108d 100644
--- a/src/core/lib/iomgr/buffer_list.cc
+++ b/src/core/lib/iomgr/buffer_list.cc
@@ -35,6 +35,9 @@ void TracedBuffer::AddNewEntry(TracedBuffer** head, uint32_t seq_no,
TracedBuffer* new_elem = New<TracedBuffer>(seq_no, arg);
/* Store the current time as the sendmsg time. */
new_elem->ts_.sendmsg_time = gpr_now(GPR_CLOCK_REALTIME);
+ new_elem->ts_.scheduled_time = gpr_inf_past(GPR_CLOCK_REALTIME);
+ new_elem->ts_.sent_time = gpr_inf_past(GPR_CLOCK_REALTIME);
+ new_elem->ts_.acked_time = gpr_inf_past(GPR_CLOCK_REALTIME);
if (*head == nullptr) {
*head = new_elem;
return;
@@ -55,10 +58,16 @@ void fill_gpr_from_timestamp(gpr_timespec* gts, const struct timespec* ts) {
gts->clock_type = GPR_CLOCK_REALTIME;
}
+void default_timestamps_callback(void* arg, grpc_core::Timestamps* ts,
+ grpc_error* shudown_err) {
+ gpr_log(GPR_DEBUG, "Timestamps callback has not been registered");
+}
+
/** The saved callback function that will be invoked when we get all the
* timestamps that we are going to get for a TracedBuffer. */
void (*timestamps_callback)(void*, grpc_core::Timestamps*,
- grpc_error* shutdown_err);
+ grpc_error* shutdown_err) =
+ default_timestamps_callback;
} /* namespace */
void TracedBuffer::ProcessTimestamp(TracedBuffer** head,
@@ -99,18 +108,20 @@ void TracedBuffer::ProcessTimestamp(TracedBuffer** head,
}
}
-void TracedBuffer::Shutdown(TracedBuffer** head, grpc_error* shutdown_err) {
+void TracedBuffer::Shutdown(TracedBuffer** head, void* remaining,
+ grpc_error* shutdown_err) {
GPR_DEBUG_ASSERT(head != nullptr);
TracedBuffer* elem = *head;
while (elem != nullptr) {
- if (timestamps_callback) {
- timestamps_callback(elem->arg_, &(elem->ts_), shutdown_err);
- }
+ timestamps_callback(elem->arg_, &(elem->ts_), shutdown_err);
auto* next = elem->next_;
Delete<TracedBuffer>(elem);
elem = next;
}
*head = nullptr;
+ if (remaining != nullptr) {
+ timestamps_callback(remaining, nullptr, shutdown_err);
+ }
GRPC_ERROR_UNREF(shutdown_err);
}
diff --git a/src/core/lib/iomgr/buffer_list.h b/src/core/lib/iomgr/buffer_list.h
index cbbf50a657..627f1bde99 100644
--- a/src/core/lib/iomgr/buffer_list.h
+++ b/src/core/lib/iomgr/buffer_list.h
@@ -37,6 +37,8 @@ struct Timestamps {
gpr_timespec scheduled_time;
gpr_timespec sent_time;
gpr_timespec acked_time;
+
+ uint32_t byte_offset; /* byte offset relative to the start of the RPC */
};
/** TracedBuffer is a class to keep track of timestamps for a specific buffer in
@@ -67,13 +69,13 @@ class TracedBuffer {
/** Cleans the list by calling the callback for each traced buffer in the list
* with timestamps that it has. */
- static void Shutdown(grpc_core::TracedBuffer** head,
+ static void Shutdown(grpc_core::TracedBuffer** head, void* remaining,
grpc_error* shutdown_err);
private:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
- TracedBuffer(int seq_no, void* arg)
+ TracedBuffer(uint32_t seq_no, void* arg)
: seq_no_(seq_no), arg_(arg), next_(nullptr) {}
uint32_t seq_no_; /* The sequence number for the last byte in the buffer */
@@ -82,7 +84,12 @@ class TracedBuffer {
grpc_core::TracedBuffer* next_; /* The next TracedBuffer in the list */
};
#else /* GRPC_LINUX_ERRQUEUE */
-class TracedBuffer {};
+class TracedBuffer {
+ public:
+ /* Dummy shutdown function */
+ static void Shutdown(grpc_core::TracedBuffer** head, void* remaining,
+ grpc_error* shutdown_err) {}
+};
#endif /* GRPC_LINUX_ERRQUEUE */
/** Sets the callback function to call when timestamps for a write are
diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc
index 00a839b64c..6b5759a036 100644
--- a/src/core/lib/iomgr/call_combiner.cc
+++ b/src/core/lib/iomgr/call_combiner.cc
@@ -39,8 +39,57 @@ static gpr_atm encode_cancel_state_error(grpc_error* error) {
return static_cast<gpr_atm>(1) | (gpr_atm)error;
}
+#ifdef GRPC_TSAN_ENABLED
+static void tsan_closure(void* user_data, grpc_error* error) {
+ grpc_call_combiner* call_combiner =
+ static_cast<grpc_call_combiner*>(user_data);
+ // We ref-count the lock, and check if it's already taken.
+ // If it was taken, we should do nothing. Otherwise, we will mark it as
+ // locked. Note that if two different threads try to do this, only one of
+ // them will be able to mark the lock as acquired, while they both run their
+ // callbacks. In such cases (which should never happen for call_combiner),
+ // TSAN will correctly produce an error.
+ //
+ // TODO(soheil): This only covers the callbacks scheduled by
+ // grpc_call_combiner_(start|finish). If in the future, a
+ // callback gets scheduled using other mechanisms, we will need
+ // to add APIs to externally lock call combiners.
+ grpc_core::RefCountedPtr<grpc_call_combiner::TsanLock> lock =
+ call_combiner->tsan_lock;
+ bool prev = false;
+ if (lock->taken.compare_exchange_strong(prev, true)) {
+ TSAN_ANNOTATE_RWLOCK_ACQUIRED(&lock->taken, true);
+ } else {
+ lock.reset();
+ }
+ GRPC_CLOSURE_RUN(call_combiner->original_closure, GRPC_ERROR_REF(error));
+ if (lock != nullptr) {
+ TSAN_ANNOTATE_RWLOCK_RELEASED(&lock->taken, true);
+ bool prev = true;
+ GPR_ASSERT(lock->taken.compare_exchange_strong(prev, false));
+ }
+}
+#endif
+
+static void call_combiner_sched_closure(grpc_call_combiner* call_combiner,
+ grpc_closure* closure,
+ grpc_error* error) {
+#ifdef GRPC_TSAN_ENABLED
+ call_combiner->original_closure = closure;
+ GRPC_CLOSURE_SCHED(&call_combiner->tsan_closure, error);
+#else
+ GRPC_CLOSURE_SCHED(closure, error);
+#endif
+}
+
void grpc_call_combiner_init(grpc_call_combiner* call_combiner) {
+ gpr_atm_no_barrier_store(&call_combiner->cancel_state, 0);
+ gpr_atm_no_barrier_store(&call_combiner->size, 0);
gpr_mpscq_init(&call_combiner->queue);
+#ifdef GRPC_TSAN_ENABLED
+ GRPC_CLOSURE_INIT(&call_combiner->tsan_closure, tsan_closure, call_combiner,
+ grpc_schedule_on_exec_ctx);
+#endif
}
void grpc_call_combiner_destroy(grpc_call_combiner* call_combiner) {
@@ -85,7 +134,7 @@ void grpc_call_combiner_start(grpc_call_combiner* call_combiner,
gpr_log(GPR_INFO, " EXECUTING IMMEDIATELY");
}
// Queue was empty, so execute this closure immediately.
- GRPC_CLOSURE_SCHED(closure, error);
+ call_combiner_sched_closure(call_combiner, closure, error);
} else {
if (grpc_call_combiner_trace.enabled()) {
gpr_log(GPR_INFO, " QUEUING");
@@ -132,7 +181,8 @@ void grpc_call_combiner_stop(grpc_call_combiner* call_combiner DEBUG_ARGS,
gpr_log(GPR_INFO, " EXECUTING FROM QUEUE: closure=%p error=%s",
closure, grpc_error_string(closure->error_data.error));
}
- GRPC_CLOSURE_SCHED(closure, closure->error_data.error);
+ call_combiner_sched_closure(call_combiner, closure,
+ closure->error_data.error);
break;
}
} else if (grpc_call_combiner_trace.enabled()) {
diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h
index 6f7ddd4043..4ec0044f05 100644
--- a/src/core/lib/iomgr/call_combiner.h
+++ b/src/core/lib/iomgr/call_combiner.h
@@ -27,7 +27,10 @@
#include "src/core/lib/gpr/mpscq.h"
#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/dynamic_annotations.h"
// A simple, lock-free mechanism for serializing activity related to a
// single call. This is similar to a combiner but is more lightweight.
@@ -40,14 +43,38 @@
extern grpc_core::TraceFlag grpc_call_combiner_trace;
-typedef struct {
- gpr_atm size; // size_t, num closures in queue or currently executing
+struct grpc_call_combiner {
+ gpr_atm size = 0; // size_t, num closures in queue or currently executing
gpr_mpscq queue;
// Either 0 (if not cancelled and no cancellation closure set),
// a grpc_closure* (if the lowest bit is 0),
// or a grpc_error* (if the lowest bit is 1).
- gpr_atm cancel_state;
-} grpc_call_combiner;
+ gpr_atm cancel_state = 0;
+#ifdef GRPC_TSAN_ENABLED
+ // A fake ref-counted lock that is kept alive after the destruction of
+ // grpc_call_combiner, when we are running the original closure.
+ //
+ // Ideally we want to lock and unlock the call combiner as a pointer, when the
+ // callback is called. However, original_closure is free to trigger
+ // anything on the call combiner (including destruction of grpc_call).
+ // Thus, we need a ref-counted structure that can outlive the call combiner.
+ struct TsanLock
+ : public grpc_core::RefCounted<TsanLock,
+ grpc_core::NonPolymorphicRefCount> {
+ TsanLock() { TSAN_ANNOTATE_RWLOCK_CREATE(&taken); }
+ ~TsanLock() { TSAN_ANNOTATE_RWLOCK_DESTROY(&taken); }
+
+ // To avoid double-locking by the same thread, we should acquire/release
+ // the lock only when taken is false. On each acquire taken must be set to
+ // true.
+ std::atomic<bool> taken{false};
+ };
+ grpc_core::RefCountedPtr<TsanLock> tsan_lock =
+ grpc_core::MakeRefCounted<TsanLock>();
+ grpc_closure tsan_closure;
+ grpc_closure* original_closure;
+#endif
+};
// Assumes memory was initialized to zero.
void grpc_call_combiner_init(grpc_call_combiner* call_combiner);
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index f14c723844..bde3437c02 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -114,6 +114,7 @@ inline grpc_closure* grpc_closure_init(grpc_closure* closure,
closure->cb = cb;
closure->cb_arg = cb_arg;
closure->scheduler = scheduler;
+ closure->error_data.error = GRPC_ERROR_NONE;
#ifndef NDEBUG
closure->scheduled = false;
closure->file_initiated = nullptr;
diff --git a/src/core/lib/iomgr/dynamic_annotations.h b/src/core/lib/iomgr/dynamic_annotations.h
new file mode 100644
index 0000000000..713928023a
--- /dev/null
+++ b/src/core/lib/iomgr/dynamic_annotations.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_DYNAMIC_ANNOTATIONS_H
+#define GRPC_CORE_LIB_IOMGR_DYNAMIC_ANNOTATIONS_H
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GRPC_TSAN_ENABLED
+
+#define TSAN_ANNOTATE_HAPPENS_BEFORE(addr) \
+ AnnotateHappensBefore(__FILE__, __LINE__, (void*)(addr))
+#define TSAN_ANNOTATE_HAPPENS_AFTER(addr) \
+ AnnotateHappensAfter(__FILE__, __LINE__, (void*)(addr))
+#define TSAN_ANNOTATE_RWLOCK_CREATE(addr) \
+ AnnotateRWLockCreate(__FILE__, __LINE__, (void*)(addr))
+#define TSAN_ANNOTATE_RWLOCK_DESTROY(addr) \
+ AnnotateRWLockDestroy(__FILE__, __LINE__, (void*)(addr))
+#define TSAN_ANNOTATE_RWLOCK_ACQUIRED(addr, is_w) \
+ AnnotateRWLockAcquired(__FILE__, __LINE__, (void*)(addr), (is_w))
+#define TSAN_ANNOTATE_RWLOCK_RELEASED(addr, is_w) \
+ AnnotateRWLockReleased(__FILE__, __LINE__, (void*)(addr), (is_w))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensBefore(const char* file, int line, const volatile void* cv);
+void AnnotateHappensAfter(const char* file, int line, const volatile void* cv);
+void AnnotateRWLockCreate(const char* file, int line,
+ const volatile void* lock);
+void AnnotateRWLockDestroy(const char* file, int line,
+ const volatile void* lock);
+void AnnotateRWLockAcquired(const char* file, int line,
+ const volatile void* lock, long is_w);
+void AnnotateRWLockReleased(const char* file, int line,
+ const volatile void* lock, long is_w);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* GRPC_TSAN_ENABLED */
+
+#define TSAN_ANNOTATE_HAPPENS_BEFORE(addr)
+#define TSAN_ANNOTATE_HAPPENS_AFTER(addr)
+#define TSAN_ANNOTATE_RWLOCK_CREATE(addr)
+#define TSAN_ANNOTATE_RWLOCK_DESTROY(addr)
+#define TSAN_ANNOTATE_RWLOCK_ACQUIRED(addr, is_w)
+#define TSAN_ANNOTATE_RWLOCK_RELEASED(addr, is_w)
+
+#endif /* GRPC_TSAN_ENABLED */
+
+#endif /* GRPC_CORE_LIB_IOMGR_DYNAMIC_ANNOTATIONS_H */
diff --git a/src/core/lib/iomgr/endpoint.cc b/src/core/lib/iomgr/endpoint.cc
index 44fb47e19d..06316c6031 100644
--- a/src/core/lib/iomgr/endpoint.cc
+++ b/src/core/lib/iomgr/endpoint.cc
@@ -61,3 +61,7 @@ int grpc_endpoint_get_fd(grpc_endpoint* ep) { return ep->vtable->get_fd(ep); }
grpc_resource_user* grpc_endpoint_get_resource_user(grpc_endpoint* ep) {
return ep->vtable->get_resource_user(ep);
}
+
+bool grpc_endpoint_can_track_err(grpc_endpoint* ep) {
+ return ep->vtable->can_track_err(ep);
+}
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 1f590a80ca..79c8ece263 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -47,6 +47,7 @@ struct grpc_endpoint_vtable {
grpc_resource_user* (*get_resource_user)(grpc_endpoint* ep);
char* (*get_peer)(grpc_endpoint* ep);
int (*get_fd)(grpc_endpoint* ep);
+ bool (*can_track_err)(grpc_endpoint* ep);
};
/* When data is available on the connection, calls the callback with slices.
@@ -95,6 +96,8 @@ void grpc_endpoint_delete_from_pollset_set(grpc_endpoint* ep,
grpc_resource_user* grpc_endpoint_get_resource_user(grpc_endpoint* endpoint);
+bool grpc_endpoint_can_track_err(grpc_endpoint* ep);
+
struct grpc_endpoint {
const grpc_endpoint_vtable* vtable;
};
diff --git a/src/core/lib/iomgr/endpoint_cfstream.cc b/src/core/lib/iomgr/endpoint_cfstream.cc
index df2cf508c8..7c4bc1ace2 100644
--- a/src/core/lib/iomgr/endpoint_cfstream.cc
+++ b/src/core/lib/iomgr/endpoint_cfstream.cc
@@ -315,6 +315,8 @@ char* CFStreamGetPeer(grpc_endpoint* ep) {
int CFStreamGetFD(grpc_endpoint* ep) { return 0; }
+bool CFStreamCanTrackErr(grpc_endpoint* ep) { return false; }
+
void CFStreamAddToPollset(grpc_endpoint* ep, grpc_pollset* pollset) {}
void CFStreamAddToPollsetSet(grpc_endpoint* ep, grpc_pollset_set* pollset) {}
void CFStreamDeleteFromPollsetSet(grpc_endpoint* ep,
@@ -329,7 +331,8 @@ static const grpc_endpoint_vtable vtable = {CFStreamRead,
CFStreamDestroy,
CFStreamGetResourceUser,
CFStreamGetPeer,
- CFStreamGetFD};
+ CFStreamGetFD,
+ CFStreamCanTrackErr};
grpc_endpoint* grpc_cfstream_endpoint_create(
CFReadStreamRef read_stream, CFWriteStreamRef write_stream,
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.cc b/src/core/lib/iomgr/endpoint_pair_posix.cc
index 3afbfd7254..5c5c246f99 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.cc
+++ b/src/core/lib/iomgr/endpoint_pair_posix.cc
@@ -59,11 +59,11 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char* name,
grpc_core::ExecCtx exec_ctx;
gpr_asprintf(&final_name, "%s:client", name);
- p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, true), args,
+ p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, false), args,
"socketpair-server");
gpr_free(final_name);
gpr_asprintf(&final_name, "%s:server", name);
- p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, true), args,
+ p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, false), args,
"socketpair-client");
gpr_free(final_name);
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index 38571b1957..4b8c891e9b 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -1242,6 +1242,8 @@ static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
* Event engine binding
*/
+static void shutdown_background_closure(void) {}
+
static void shutdown_engine(void) {
fd_global_shutdown();
pollset_global_shutdown();
@@ -1255,6 +1257,7 @@ static void shutdown_engine(void) {
static const grpc_event_engine_vtable vtable = {
sizeof(grpc_pollset),
true,
+ false,
fd_create,
fd_wrapped_fd,
@@ -1284,6 +1287,7 @@ static const grpc_event_engine_vtable vtable = {
pollset_set_add_fd,
pollset_set_del_fd,
+ shutdown_background_closure,
shutdown_engine,
};
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index 06a382c556..7a4870db78 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -1604,6 +1604,8 @@ static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
* Event engine binding
*/
+static void shutdown_background_closure(void) {}
+
static void shutdown_engine(void) {
fd_global_shutdown();
pollset_global_shutdown();
@@ -1612,6 +1614,7 @@ static void shutdown_engine(void) {
static const grpc_event_engine_vtable vtable = {
sizeof(grpc_pollset),
true,
+ false,
fd_create,
fd_wrapped_fd,
@@ -1641,6 +1644,7 @@ static const grpc_event_engine_vtable vtable = {
pollset_set_add_fd,
pollset_set_del_fd,
+ shutdown_background_closure,
shutdown_engine,
};
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index 16562538a6..67cbfbbd02 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -1782,6 +1782,8 @@ static void global_cv_fd_table_shutdown() {
* event engine binding
*/
+static void shutdown_background_closure(void) {}
+
static void shutdown_engine(void) {
pollset_global_shutdown();
if (grpc_cv_wakeup_fds_enabled()) {
@@ -1796,6 +1798,7 @@ static void shutdown_engine(void) {
static const grpc_event_engine_vtable vtable = {
sizeof(grpc_pollset),
false,
+ false,
fd_create,
fd_wrapped_fd,
@@ -1825,6 +1828,7 @@ static const grpc_event_engine_vtable vtable = {
pollset_set_add_fd,
pollset_set_del_fd,
+ shutdown_background_closure,
shutdown_engine,
};
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index 8a7dc7b004..32d1b6c43e 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -36,6 +36,7 @@
#include "src/core/lib/iomgr/ev_epoll1_linux.h"
#include "src/core/lib/iomgr/ev_epollex_linux.h"
#include "src/core/lib/iomgr/ev_poll_posix.h"
+#include "src/core/lib/iomgr/internal_errqueue.h"
grpc_core::TraceFlag grpc_polling_trace(false,
"polling"); /* Disabled by default */
@@ -236,19 +237,22 @@ void grpc_event_engine_shutdown(void) {
}
bool grpc_event_engine_can_track_errors(void) {
-/* Only track errors if platform supports errqueue. */
-#ifdef GRPC_LINUX_ERRQUEUE
- return g_event_engine->can_track_err;
-#else
+ /* Only track errors if platform supports errqueue. */
+ if (grpc_core::kernel_supports_errqueue()) {
+ return g_event_engine->can_track_err;
+ }
return false;
-#endif /* GRPC_LINUX_ERRQUEUE */
+}
+
+bool grpc_event_engine_run_in_background(void) {
+ return g_event_engine->run_in_background;
}
grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err) {
GRPC_POLLING_API_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
GRPC_FD_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
- return g_event_engine->fd_create(fd, name,
- track_err && g_event_engine->can_track_err);
+ return g_event_engine->fd_create(
+ fd, name, track_err && grpc_event_engine_can_track_errors());
}
int grpc_fd_wrapped_fd(grpc_fd* fd) {
@@ -395,4 +399,8 @@ void grpc_pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
g_event_engine->pollset_set_del_fd(pollset_set, fd);
}
+void grpc_shutdown_background_closure(void) {
+ g_event_engine->shutdown_background_closure();
+}
+
#endif // GRPC_POSIX_SOCKET_EV
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index b8fb8f534b..812c7a0f0f 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -42,6 +42,7 @@ typedef struct grpc_fd grpc_fd;
typedef struct grpc_event_engine_vtable {
size_t pollset_size;
bool can_track_err;
+ bool run_in_background;
grpc_fd* (*fd_create)(int fd, const char* name, bool track_err);
int (*fd_wrapped_fd)(grpc_fd* fd);
@@ -79,6 +80,7 @@ typedef struct grpc_event_engine_vtable {
void (*pollset_set_add_fd)(grpc_pollset_set* pollset_set, grpc_fd* fd);
void (*pollset_set_del_fd)(grpc_pollset_set* pollset_set, grpc_fd* fd);
+ void (*shutdown_background_closure)(void);
void (*shutdown_engine)(void);
} grpc_event_engine_vtable;
@@ -101,6 +103,11 @@ const char* grpc_get_poll_strategy_name();
*/
bool grpc_event_engine_can_track_errors();
+/* Returns true if polling engine runs in the background, false otherwise.
+ * Currently only 'epollbg' runs in the background.
+ */
+bool grpc_event_engine_run_in_background();
+
/* Create a wrapped file descriptor.
Requires fd is a non-blocking file descriptor.
\a track_err if true means that error events would be tracked separately
@@ -174,6 +181,9 @@ void grpc_pollset_add_fd(grpc_pollset* pollset, struct grpc_fd* fd);
void grpc_pollset_set_add_fd(grpc_pollset_set* pollset_set, grpc_fd* fd);
void grpc_pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd);
+/* Shut down all the closures registered in the background poller. */
+void grpc_shutdown_background_closure();
+
/* override to allow tests to hook poll() usage */
typedef int (*grpc_poll_function_type)(struct pollfd*, nfds_t, int);
extern grpc_poll_function_type grpc_poll_function;
diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc
index e957bad73d..05ecd2a49b 100644
--- a/src/core/lib/iomgr/fork_posix.cc
+++ b/src/core/lib/iomgr/fork_posix.cc
@@ -60,7 +60,7 @@ void grpc_prefork() {
}
if (strcmp(grpc_get_poll_strategy_name(), "epoll1") != 0 &&
strcmp(grpc_get_poll_strategy_name(), "poll") != 0) {
- gpr_log(GPR_ERROR,
+ gpr_log(GPR_INFO,
"Fork support is only compatible with the epoll1 and poll polling "
"strategies");
}
diff --git a/src/core/lib/iomgr/internal_errqueue.cc b/src/core/lib/iomgr/internal_errqueue.cc
index 99c22e9055..982d709f09 100644
--- a/src/core/lib/iomgr/internal_errqueue.cc
+++ b/src/core/lib/iomgr/internal_errqueue.cc
@@ -20,17 +20,50 @@
#include "src/core/lib/iomgr/port.h"
+#include <grpc/impl/codegen/log.h>
#include "src/core/lib/iomgr/internal_errqueue.h"
#ifdef GRPC_POSIX_SOCKET_TCP
-bool kernel_supports_errqueue() {
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+namespace grpc_core {
+static bool errqueue_supported = false;
+
+bool kernel_supports_errqueue() { return errqueue_supported; }
+
+void grpc_errqueue_init() {
+/* Both-compile time and run-time linux kernel versions should be atleast 4.0.0
+ */
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
- return true;
+ struct utsname buffer;
+ if (uname(&buffer) != 0) {
+ gpr_log(GPR_ERROR, "uname: %s", strerror(errno));
+ return;
+ }
+ char* release = buffer.release;
+ if (release == nullptr) {
+ return;
+ }
+
+ if (strtol(release, nullptr, 10) >= 4) {
+ errqueue_supported = true;
+ } else {
+ gpr_log(GPR_DEBUG, "ERRQUEUE support not enabled");
+ }
#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4, 0, 0) */
#endif /* LINUX_VERSION_CODE */
- return false;
}
+} /* namespace grpc_core */
+
+#else
+
+namespace grpc_core {
+void grpc_errqueue_init() {}
+} /* namespace grpc_core */
#endif /* GRPC_POSIX_SOCKET_TCP */
diff --git a/src/core/lib/iomgr/internal_errqueue.h b/src/core/lib/iomgr/internal_errqueue.h
index 9d122808f9..f8644c2536 100644
--- a/src/core/lib/iomgr/internal_errqueue.h
+++ b/src/core/lib/iomgr/internal_errqueue.h
@@ -76,8 +76,14 @@ constexpr uint32_t kTimestampingRecordingOptions =
* Currently allowing only linux kernels above 4.0.0
*/
bool kernel_supports_errqueue();
-} // namespace grpc_core
+
+} /* namespace grpc_core */
#endif /* GRPC_POSIX_SOCKET_TCP */
+namespace grpc_core {
+/* Initializes errqueue support */
+void grpc_errqueue_init();
+} /* namespace grpc_core */
+
#endif /* GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H */
diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc
index 46afda1774..eb29973514 100644
--- a/src/core/lib/iomgr/iomgr.cc
+++ b/src/core/lib/iomgr/iomgr.cc
@@ -33,8 +33,10 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/iomgr/buffer_list.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/internal_errqueue.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/network_status_tracker.h"
#include "src/core/lib/iomgr/timer.h"
@@ -57,6 +59,7 @@ void grpc_iomgr_init() {
g_root_object.name = (char*)"root";
grpc_network_status_init();
grpc_iomgr_platform_init();
+ grpc_core::grpc_errqueue_init();
}
void grpc_iomgr_start() { grpc_timer_manager_init(); }
@@ -154,6 +157,10 @@ void grpc_iomgr_shutdown() {
gpr_cv_destroy(&g_rcv);
}
+void grpc_iomgr_shutdown_background_closure() {
+ grpc_iomgr_platform_shutdown_background_closure();
+}
+
void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name) {
obj->name = gpr_strdup(name);
gpr_mu_lock(&g_mu);
diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h
index 537ef8a6ff..8ea9289e06 100644
--- a/src/core/lib/iomgr/iomgr.h
+++ b/src/core/lib/iomgr/iomgr.h
@@ -35,6 +35,10 @@ void grpc_iomgr_start();
* exec_ctx. */
void grpc_iomgr_shutdown();
+/** Signals the intention to shutdown all the closures registered in the
+ * background poller. */
+void grpc_iomgr_shutdown_background_closure();
+
/* Exposed only for testing */
size_t grpc_iomgr_count_objects_for_testing();
diff --git a/src/core/lib/iomgr/iomgr_custom.cc b/src/core/lib/iomgr/iomgr_custom.cc
index d34c8e7cd1..4b112c9097 100644
--- a/src/core/lib/iomgr/iomgr_custom.cc
+++ b/src/core/lib/iomgr/iomgr_custom.cc
@@ -40,9 +40,11 @@ static void iomgr_platform_init(void) {
}
static void iomgr_platform_flush(void) {}
static void iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); }
+static void iomgr_platform_shutdown_background_closure(void) {}
static grpc_iomgr_platform_vtable vtable = {
- iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown,
+ iomgr_platform_shutdown_background_closure};
void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
grpc_custom_resolver_vtable* resolver,
diff --git a/src/core/lib/iomgr/iomgr_internal.cc b/src/core/lib/iomgr/iomgr_internal.cc
index 32dbabb79d..b6c9211865 100644
--- a/src/core/lib/iomgr/iomgr_internal.cc
+++ b/src/core/lib/iomgr/iomgr_internal.cc
@@ -41,3 +41,7 @@ void grpc_iomgr_platform_init() { iomgr_platform_vtable->init(); }
void grpc_iomgr_platform_flush() { iomgr_platform_vtable->flush(); }
void grpc_iomgr_platform_shutdown() { iomgr_platform_vtable->shutdown(); }
+
+void grpc_iomgr_platform_shutdown_background_closure() {
+ iomgr_platform_vtable->shutdown_background_closure();
+}
diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h
index b011d9c7b1..bca7409907 100644
--- a/src/core/lib/iomgr/iomgr_internal.h
+++ b/src/core/lib/iomgr/iomgr_internal.h
@@ -35,6 +35,7 @@ typedef struct grpc_iomgr_platform_vtable {
void (*init)(void);
void (*flush)(void);
void (*shutdown)(void);
+ void (*shutdown_background_closure)(void);
} grpc_iomgr_platform_vtable;
void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name);
@@ -52,6 +53,9 @@ void grpc_iomgr_platform_flush(void);
/** tear down all platform specific global iomgr structures */
void grpc_iomgr_platform_shutdown(void);
+/** shut down all the closures registered in the background poller */
+void grpc_iomgr_platform_shutdown_background_closure(void);
+
bool grpc_iomgr_abort_on_leaks(void);
#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/iomgr_posix.cc b/src/core/lib/iomgr/iomgr_posix.cc
index ca7334c9a4..9386adf060 100644
--- a/src/core/lib/iomgr/iomgr_posix.cc
+++ b/src/core/lib/iomgr/iomgr_posix.cc
@@ -51,8 +51,13 @@ static void iomgr_platform_shutdown(void) {
grpc_wakeup_fd_global_destroy();
}
+static void iomgr_platform_shutdown_background_closure(void) {
+ grpc_shutdown_background_closure();
+}
+
static grpc_iomgr_platform_vtable vtable = {
- iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown,
+ iomgr_platform_shutdown_background_closure};
void grpc_set_default_iomgr_platform() {
grpc_set_tcp_client_impl(&grpc_posix_tcp_client_vtable);
diff --git a/src/core/lib/iomgr/iomgr_posix_cfstream.cc b/src/core/lib/iomgr/iomgr_posix_cfstream.cc
index 235a9e0712..552ef4309c 100644
--- a/src/core/lib/iomgr/iomgr_posix_cfstream.cc
+++ b/src/core/lib/iomgr/iomgr_posix_cfstream.cc
@@ -54,8 +54,13 @@ static void iomgr_platform_shutdown(void) {
grpc_wakeup_fd_global_destroy();
}
+static void iomgr_platform_shutdown_background_closure(void) {
+ grpc_shutdown_background_closure();
+}
+
static grpc_iomgr_platform_vtable vtable = {
- iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown,
+ iomgr_platform_shutdown_background_closure};
void grpc_set_default_iomgr_platform() {
char* enable_cfstream = getenv(grpc_cfstream_env_var);
diff --git a/src/core/lib/iomgr/iomgr_windows.cc b/src/core/lib/iomgr/iomgr_windows.cc
index cdef89cbf0..24ef0dba7b 100644
--- a/src/core/lib/iomgr/iomgr_windows.cc
+++ b/src/core/lib/iomgr/iomgr_windows.cc
@@ -71,8 +71,11 @@ static void iomgr_platform_shutdown(void) {
winsock_shutdown();
}
+static void iomgr_platform_shutdown_background_closure(void) {}
+
static grpc_iomgr_platform_vtable vtable = {
- iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown,
+ iomgr_platform_shutdown_background_closure};
void grpc_set_default_iomgr_platform() {
grpc_set_tcp_client_impl(&grpc_windows_tcp_client_vtable);
diff --git a/src/core/lib/iomgr/polling_entity.h b/src/core/lib/iomgr/polling_entity.h
index a95e08524c..6f4c5bdd66 100644
--- a/src/core/lib/iomgr/polling_entity.h
+++ b/src/core/lib/iomgr/polling_entity.h
@@ -34,13 +34,13 @@ typedef enum grpc_pollset_tag {
* functions that accept a pollset XOR a pollset_set to do so through an
* abstract interface. No ownership is taken. */
-typedef struct grpc_polling_entity {
+struct grpc_polling_entity {
union {
- grpc_pollset* pollset;
+ grpc_pollset* pollset = nullptr;
grpc_pollset_set* pollset_set;
} pollent;
- grpc_pollset_tag tag;
-} grpc_polling_entity;
+ grpc_pollset_tag tag = GRPC_POLLS_NONE;
+};
grpc_polling_entity grpc_polling_entity_create_from_pollset_set(
grpc_pollset_set* pollset_set);
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index bf56a7298d..c8046b21dc 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -62,8 +62,7 @@
#define GRPC_HAVE_UNIX_SOCKET 1
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-/* TODO(yashykt): Re-enable once Fathom changes are commited.
-#define GRPC_LINUX_ERRQUEUE 1 */
+#define GRPC_LINUX_ERRQUEUE 1
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
#endif /* LINUX_VERSION_CODE */
#define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index 6afe94a7a9..7016ffc31a 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -65,7 +65,7 @@ void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable);
/* Asynchronously resolve addr. Use default_port if a port isn't designated
in addr, otherwise use the port in addr. */
-/* TODO(ctiller): add a timeout here */
+/* TODO(apolcyn): add a timeout here */
void grpc_resolve_address(const char* addr, const char* default_port,
grpc_pollset_set* interested_parties,
grpc_closure* on_done,
diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc
index b6fc7579f7..7e4b3c9b2f 100644
--- a/src/core/lib/iomgr/resource_quota.cc
+++ b/src/core/lib/iomgr/resource_quota.cc
@@ -90,7 +90,8 @@ struct grpc_resource_user {
grpc_closure_list on_allocated;
/* True if we are currently trying to allocate from the quota, false if not */
bool allocating;
- /* How many bytes of allocations are outstanding */
+ /* The amount of memory (in bytes) that has been requested from this user
+ * asynchronously but hasn't been granted yet. */
int64_t outstanding_allocations;
/* True if we are currently trying to add ourselves to the non-free quota
list, false otherwise */
@@ -135,6 +136,9 @@ struct grpc_resource_quota {
int64_t size;
/* Amount of free memory in the resource quota */
int64_t free_pool;
+ /* Used size of memory in the resource quota. Updated as soon as the resource
+ * users start to allocate or free the memory. */
+ gpr_atm used;
gpr_atm last_size;
@@ -371,6 +375,7 @@ static bool rq_reclaim_from_per_user_free_pool(
while ((resource_user = rulist_pop_head(resource_quota,
GRPC_RULIST_NON_EMPTY_FREE_POOL))) {
gpr_mu_lock(&resource_user->mu);
+ resource_user->added_to_free_pool = false;
if (resource_user->free_pool > 0) {
int64_t amt = resource_user->free_pool;
resource_user->free_pool = 0;
@@ -386,6 +391,13 @@ static bool rq_reclaim_from_per_user_free_pool(
gpr_mu_unlock(&resource_user->mu);
return true;
} else {
+ if (grpc_resource_quota_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "RQ %s %s: failed to reclaim_from_per_user_free_pool; "
+ "free_pool = %" PRId64 "; rq_free_pool = %" PRId64,
+ resource_quota->name, resource_user->name,
+ resource_user->free_pool, resource_quota->free_pool);
+ }
gpr_mu_unlock(&resource_user->mu);
}
}
@@ -622,6 +634,7 @@ grpc_resource_quota* grpc_resource_quota_create(const char* name) {
resource_quota->combiner = grpc_combiner_create();
resource_quota->free_pool = INT64_MAX;
resource_quota->size = INT64_MAX;
+ resource_quota->used = 0;
gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
gpr_mu_init(&resource_quota->thread_count_mu);
resource_quota->max_threads = INT_MAX;
@@ -712,7 +725,7 @@ size_t grpc_resource_quota_peek_size(grpc_resource_quota* resource_quota) {
*/
grpc_resource_quota* grpc_resource_quota_from_channel_args(
- const grpc_channel_args* channel_args) {
+ const grpc_channel_args* channel_args, bool create) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
if (channel_args->args[i].type == GRPC_ARG_POINTER) {
@@ -724,7 +737,7 @@ grpc_resource_quota* grpc_resource_quota_from_channel_args(
}
}
}
- return grpc_resource_quota_create(nullptr);
+ return create ? grpc_resource_quota_create(nullptr) : nullptr;
}
static void* rq_copy(void* rq) {
@@ -863,33 +876,68 @@ void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
gpr_mu_unlock(&resource_user->resource_quota->thread_count_mu);
}
-void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
- grpc_closure* optional_on_done) {
- gpr_mu_lock(&resource_user->mu);
+static void resource_user_alloc_locked(grpc_resource_user* resource_user,
+ size_t size,
+ grpc_closure* optional_on_done) {
ru_ref_by(resource_user, static_cast<gpr_atm>(size));
resource_user->free_pool -= static_cast<int64_t>(size);
- resource_user->outstanding_allocations += static_cast<int64_t>(size);
if (grpc_resource_quota_trace.enabled()) {
gpr_log(GPR_INFO, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
resource_user->resource_quota->name, resource_user->name, size,
resource_user->free_pool);
}
if (resource_user->free_pool < 0) {
- grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
- GRPC_ERROR_NONE);
+ if (optional_on_done != nullptr) {
+ resource_user->outstanding_allocations += static_cast<int64_t>(size);
+ grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
+ GRPC_ERROR_NONE);
+ }
if (!resource_user->allocating) {
resource_user->allocating = true;
GRPC_CLOSURE_SCHED(&resource_user->allocate_closure, GRPC_ERROR_NONE);
}
} else {
- resource_user->outstanding_allocations -= static_cast<int64_t>(size);
GRPC_CLOSURE_SCHED(optional_on_done, GRPC_ERROR_NONE);
}
+}
+
+bool grpc_resource_user_safe_alloc(grpc_resource_user* resource_user,
+ size_t size) {
+ if (gpr_atm_no_barrier_load(&resource_user->shutdown)) return false;
+ gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ bool cas_success;
+ do {
+ gpr_atm used = gpr_atm_no_barrier_load(&resource_quota->used);
+ gpr_atm new_used = used + size;
+ if (static_cast<size_t>(new_used) >
+ grpc_resource_quota_peek_size(resource_quota)) {
+ gpr_mu_unlock(&resource_user->mu);
+ return false;
+ }
+ cas_success = gpr_atm_full_cas(&resource_quota->used, used, new_used);
+ } while (!cas_success);
+ resource_user_alloc_locked(resource_user, size, nullptr);
+ gpr_mu_unlock(&resource_user->mu);
+ return true;
+}
+
+void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
+ grpc_closure* optional_on_done) {
+ // TODO(juanlishen): Maybe return immediately if shutting down. Deferring this
+ // because some tests become flaky after the change.
+ gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ gpr_atm_no_barrier_fetch_add(&resource_quota->used, size);
+ resource_user_alloc_locked(resource_user, size, optional_on_done);
gpr_mu_unlock(&resource_user->mu);
}
void grpc_resource_user_free(grpc_resource_user* resource_user, size_t size) {
gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ gpr_atm prior = gpr_atm_no_barrier_fetch_add(&resource_quota->used, -size);
+ GPR_ASSERT(prior >= static_cast<long>(size));
bool was_zero_or_negative = resource_user->free_pool <= 0;
resource_user->free_pool += static_cast<int64_t>(size);
if (grpc_resource_quota_trace.enabled()) {
@@ -940,6 +988,12 @@ void grpc_resource_user_slice_allocator_init(
void grpc_resource_user_alloc_slices(
grpc_resource_user_slice_allocator* slice_allocator, size_t length,
size_t count, grpc_slice_buffer* dest) {
+ if (gpr_atm_no_barrier_load(&slice_allocator->resource_user->shutdown)) {
+ GRPC_CLOSURE_SCHED(
+ &slice_allocator->on_allocated,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource user shutdown"));
+ return;
+ }
slice_allocator->length = length;
slice_allocator->count = count;
slice_allocator->dest = dest;
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index 7b0ed7417a..1c79b52e3f 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -65,11 +65,16 @@
extern grpc_core::TraceFlag grpc_resource_quota_trace;
+// TODO(juanlishen): This is a hack. We need to do real accounting instead of
+// hard coding.
+constexpr size_t GRPC_RESOURCE_QUOTA_CALL_SIZE = 15 * 1024;
+constexpr size_t GRPC_RESOURCE_QUOTA_CHANNEL_SIZE = 50 * 1024;
+
grpc_resource_quota* grpc_resource_quota_ref_internal(
grpc_resource_quota* resource_quota);
void grpc_resource_quota_unref_internal(grpc_resource_quota* resource_quota);
grpc_resource_quota* grpc_resource_quota_from_channel_args(
- const grpc_channel_args* channel_args);
+ const grpc_channel_args* channel_args, bool create = true);
/* Return a number indicating current memory pressure:
0.0 ==> no memory usage
@@ -109,11 +114,21 @@ bool grpc_resource_user_allocate_threads(grpc_resource_user* resource_user,
void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
int thread_count);
-/* Allocate from the resource user (and its quota).
- If optional_on_done is NULL, then allocate immediately. This may push the
- quota over-limit, at which point reclamation will kick in.
- If optional_on_done is non-NULL, it will be scheduled when the allocation has
- been granted by the quota. */
+/* Allocates from the resource user 'size' worth of memory if this won't exceed
+ * the resource quota's total size. Returns whether the allocation is done
+ * successfully. If allocated successfully, the memory should be freed by the
+ * caller eventually. */
+bool grpc_resource_user_safe_alloc(grpc_resource_user* resource_user,
+ size_t size);
+/* Allocates from the resource user 'size' worth of memory.
+ * If optional_on_done is NULL, then allocate immediately. This may push the
+ * quota over-limit, at which point reclamation will kick in. The caller is
+ * always responsible to free the memory eventually.
+ * If optional_on_done is non-NULL, it will be scheduled without error when the
+ * allocation has been granted by the quota, and the caller is responsible to
+ * free the memory eventually. Or it may be scheduled with an error, in which
+ * case the caller fails to allocate the memory and shouldn't free the memory.
+ */
void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
grpc_closure* optional_on_done);
/* Release memory back to the quota */
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index bdfc1d70c3..4c337a0521 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -296,14 +296,17 @@ grpc_error* grpc_set_socket_tcp_user_timeout(
socklen_t len = sizeof(newval);
if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
sizeof(timeout))) {
- return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)");
+ gpr_log(GPR_ERROR, "setsockopt(TCP_USER_TIMEOUT) %s", strerror(errno));
+ return GRPC_ERROR_NONE;
}
if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
- return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)");
+ gpr_log(GPR_ERROR, "getsockopt(TCP_USER_TIMEOUT) %s", strerror(errno));
+ return GRPC_ERROR_NONE;
}
if (newval != timeout) {
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to set TCP_USER_TIMEOUT");
+ /* Do not fail on failing to set TCP_USER_TIMEOUT for now. */
+ gpr_log(GPR_ERROR, "Failed to set TCP_USER_TIMEOUT");
+ return GRPC_ERROR_NONE;
}
}
#else
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 8553ed0db4..0bff74e88b 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -76,6 +76,8 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_reuse_addr(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
true /* is_client */);
if (err != GRPC_ERROR_NONE) goto error;
diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc
index e02a1898f2..f7a5f36cdc 100644
--- a/src/core/lib/iomgr/tcp_custom.cc
+++ b/src/core/lib/iomgr/tcp_custom.cc
@@ -326,6 +326,8 @@ static grpc_resource_user* endpoint_get_resource_user(grpc_endpoint* ep) {
static int endpoint_get_fd(grpc_endpoint* ep) { return -1; }
+static bool endpoint_can_track_err(grpc_endpoint* ep) { return false; }
+
static grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_write,
endpoint_add_to_pollset,
@@ -335,7 +337,8 @@ static grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_destroy,
endpoint_get_resource_user,
endpoint_get_peer,
- endpoint_get_fd};
+ endpoint_get_fd,
+ endpoint_can_track_err};
grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket,
grpc_resource_quota* resource_quota,
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index aa2704ce26..cfcb190d60 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -260,10 +260,17 @@ static void notify_on_write(grpc_tcp* tcp) {
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p notify_on_write", tcp);
}
- cover_self(tcp);
- GRPC_CLOSURE_INIT(&tcp->write_done_closure,
- tcp_drop_uncovered_then_handle_write, tcp,
- grpc_schedule_on_exec_ctx);
+ if (grpc_event_engine_run_in_background()) {
+ // If there is a polling engine always running in the background, there is
+ // no need to run the backup poller.
+ GRPC_CLOSURE_INIT(&tcp->write_done_closure, tcp_handle_write, tcp,
+ grpc_schedule_on_exec_ctx);
+ } else {
+ cover_self(tcp);
+ GRPC_CLOSURE_INIT(&tcp->write_done_closure,
+ tcp_drop_uncovered_then_handle_write, tcp,
+ grpc_schedule_on_exec_ctx);
+ }
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_done_closure);
}
@@ -384,6 +391,12 @@ static void tcp_destroy(grpc_endpoint* ep) {
grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
if (grpc_event_engine_can_track_errors()) {
+ gpr_mu_lock(&tcp->tb_mu);
+ grpc_core::TracedBuffer::Shutdown(
+ &tcp->tb_head, tcp->outgoing_buffer_arg,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
+ gpr_mu_unlock(&tcp->tb_mu);
+ tcp->outgoing_buffer_arg = nullptr;
gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
grpc_fd_set_error(tcp->em_fd);
}
@@ -621,7 +634,7 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
if (sending_length == static_cast<size_t>(length)) {
gpr_mu_lock(&tcp->tb_mu);
grpc_core::TracedBuffer::AddNewEntry(
- &tcp->tb_head, static_cast<int>(tcp->bytes_counter + length),
+ &tcp->tb_head, static_cast<uint32_t>(tcp->bytes_counter + length),
tcp->outgoing_buffer_arg);
gpr_mu_unlock(&tcp->tb_mu);
tcp->outgoing_buffer_arg = nullptr;
@@ -673,11 +686,9 @@ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg,
}
/** For linux platforms, reads the socket's error queue and processes error
- * messages from the queue. Returns true if all the errors processed were
- * timestamps. Returns false if any of the errors were not timestamps. For
- * non-linux platforms, error processing is not used/enabled currently.
+ * messages from the queue.
*/
-static bool process_errors(grpc_tcp* tcp) {
+static void process_errors(grpc_tcp* tcp) {
while (true) {
struct iovec iov;
iov.iov_base = nullptr;
@@ -706,10 +717,10 @@ static bool process_errors(grpc_tcp* tcp) {
} while (r < 0 && saved_errno == EINTR);
if (r == -1 && saved_errno == EAGAIN) {
- return true; /* No more errors to process */
+ return; /* No more errors to process */
}
if (r == -1) {
- return false;
+ return;
}
if (grpc_tcp_trace.enabled()) {
if ((msg.msg_flags & MSG_CTRUNC) == 1) {
@@ -719,8 +730,9 @@ static bool process_errors(grpc_tcp* tcp) {
if (msg.msg_controllen == 0) {
/* There was no control message found. It was probably spurious. */
- return true;
+ return;
}
+ bool seen = false;
for (auto cmsg = CMSG_FIRSTHDR(&msg); cmsg && cmsg->cmsg_len;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_SOCKET ||
@@ -732,9 +744,13 @@ static bool process_errors(grpc_tcp* tcp) {
"unknown control message cmsg_level:%d cmsg_type:%d",
cmsg->cmsg_level, cmsg->cmsg_type);
}
- return false;
+ return;
}
- process_timestamp(tcp, &msg, cmsg);
+ cmsg = process_timestamp(tcp, &msg, cmsg);
+ seen = true;
+ }
+ if (!seen) {
+ return;
}
}
}
@@ -749,20 +765,17 @@ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
static_cast<bool>(gpr_atm_acq_load(&tcp->stop_error_notification))) {
/* We aren't going to register to hear on error anymore, so it is safe to
* unref. */
- grpc_core::TracedBuffer::Shutdown(&tcp->tb_head, GRPC_ERROR_REF(error));
TCP_UNREF(tcp, "error-tracking");
return;
}
/* We are still interested in collecting timestamps, so let's try reading
* them. */
- if (!process_errors(tcp)) {
- /* This was not a timestamps error. This was an actual error. Set the
- * read and write closures to be ready.
- */
- grpc_fd_set_readable(tcp->em_fd);
- grpc_fd_set_writable(tcp->em_fd);
- }
+ process_errors(tcp);
+ /* This might not a timestamps error. Set the read and write closures to be
+ * ready. */
+ grpc_fd_set_readable(tcp->em_fd);
+ grpc_fd_set_writable(tcp->em_fd);
GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp,
grpc_schedule_on_exec_ctx);
grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure);
@@ -784,6 +797,19 @@ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
}
#endif /* GRPC_LINUX_ERRQUEUE */
+/* If outgoing_buffer_arg is filled, shuts down the list early, so that any
+ * release operations needed can be performed on the arg */
+void tcp_shutdown_buffer_list(grpc_tcp* tcp) {
+ if (tcp->outgoing_buffer_arg) {
+ gpr_mu_lock(&tcp->tb_mu);
+ grpc_core::TracedBuffer::Shutdown(
+ &tcp->tb_head, tcp->outgoing_buffer_arg,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
+ gpr_mu_unlock(&tcp->tb_mu);
+ tcp->outgoing_buffer_arg = nullptr;
+ }
+}
+
/* returns true if done, false if pending; if returning true, *error is set */
#if defined(IOV_MAX) && IOV_MAX < 1000
#define MAX_WRITE_IOVEC IOV_MAX
@@ -831,8 +857,10 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
msg.msg_flags = 0;
if (tcp->outgoing_buffer_arg != nullptr) {
if (!tcp_write_with_timestamps(tcp, &msg, sending_length, &sent_length,
- error))
+ error)) {
+ tcp_shutdown_buffer_list(tcp);
return true; /* something went wrong with timestamps */
+ }
} else {
msg.msg_control = nullptr;
msg.msg_controllen = 0;
@@ -856,10 +884,12 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
} else if (errno == EPIPE) {
*error = tcp_annotate_error(GRPC_OS_ERROR(errno, "sendmsg"), tcp);
grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
+ tcp_shutdown_buffer_list(tcp);
return true;
} else {
*error = tcp_annotate_error(GRPC_OS_ERROR(errno, "sendmsg"), tcp);
grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
+ tcp_shutdown_buffer_list(tcp);
return true;
}
}
@@ -936,17 +966,18 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
GPR_ASSERT(tcp->write_cb == nullptr);
+ tcp->outgoing_buffer_arg = arg;
if (buf->length == 0) {
GRPC_CLOSURE_SCHED(
cb, grpc_fd_is_shutdown(tcp->em_fd)
? tcp_annotate_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"), tcp)
: GRPC_ERROR_NONE);
+ tcp_shutdown_buffer_list(tcp);
return;
}
tcp->outgoing_buffer = buf;
tcp->outgoing_byte_idx = 0;
- tcp->outgoing_buffer_arg = arg;
if (arg) {
GPR_ASSERT(grpc_event_engine_can_track_errors());
}
@@ -999,6 +1030,22 @@ static grpc_resource_user* tcp_get_resource_user(grpc_endpoint* ep) {
return tcp->resource_user;
}
+static bool tcp_can_track_err(grpc_endpoint* ep) {
+ grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
+ if (!grpc_event_engine_can_track_errors()) {
+ return false;
+ }
+ struct sockaddr addr;
+ socklen_t len = sizeof(addr);
+ if (getsockname(tcp->fd, &addr, &len) < 0) {
+ return false;
+ }
+ if (addr.sa_family == AF_INET || addr.sa_family == AF_INET6) {
+ return true;
+ }
+ return false;
+}
+
static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_write,
tcp_add_to_pollset,
@@ -1008,7 +1055,8 @@ static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_destroy,
tcp_get_resource_user,
tcp_get_peer,
- tcp_get_fd};
+ tcp_get_fd,
+ tcp_can_track_err};
#define MAX_CHUNK_SIZE 32 * 1024 * 1024
@@ -1069,6 +1117,7 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd,
tcp->is_first_read = true;
tcp->bytes_counter = -1;
tcp->socket_ts_enabled = false;
+ tcp->outgoing_buffer_arg = nullptr;
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);
gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
@@ -1113,6 +1162,12 @@ void grpc_tcp_destroy_and_release_fd(grpc_endpoint* ep, int* fd,
grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
if (grpc_event_engine_can_track_errors()) {
/* Stop errors notification. */
+ gpr_mu_lock(&tcp->tb_mu);
+ grpc_core::TracedBuffer::Shutdown(
+ &tcp->tb_head, tcp->outgoing_buffer_arg,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
+ gpr_mu_unlock(&tcp->tb_mu);
+ tcp->outgoing_buffer_arg = nullptr;
gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
grpc_fd_set_error(tcp->em_fd);
}
diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc
index 64c4a56ae9..86ee1010cf 100644
--- a/src/core/lib/iomgr/tcp_windows.cc
+++ b/src/core/lib/iomgr/tcp_windows.cc
@@ -42,6 +42,7 @@
#include "src/core/lib/iomgr/tcp_windows.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#if defined(__MSYS__) && defined(GPR_ARCH_64)
/* Nasty workaround for nasty bug when using the 64 bits msys compiler
@@ -112,7 +113,10 @@ typedef struct grpc_tcp {
grpc_closure* read_cb;
grpc_closure* write_cb;
- grpc_slice read_slice;
+
+ /* garbage after the last read */
+ grpc_slice_buffer last_read_buffer;
+
grpc_slice_buffer* write_slices;
grpc_slice_buffer* read_slices;
@@ -131,6 +135,7 @@ static void tcp_free(grpc_tcp* tcp) {
grpc_winsocket_destroy(tcp->socket);
gpr_mu_destroy(&tcp->mu);
gpr_free(tcp->peer_string);
+ grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
grpc_resource_user_unref(tcp->resource_user);
if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error);
gpr_free(tcp);
@@ -179,9 +184,12 @@ static void on_read(void* tcpp, grpc_error* error) {
grpc_tcp* tcp = (grpc_tcp*)tcpp;
grpc_closure* cb = tcp->read_cb;
grpc_winsocket* socket = tcp->socket;
- grpc_slice sub;
grpc_winsocket_callback_info* info = &socket->read_info;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP:%p on_read", tcp);
+ }
+
GRPC_ERROR_REF(error);
if (error == GRPC_ERROR_NONE) {
@@ -189,13 +197,35 @@ static void on_read(void* tcpp, grpc_error* error) {
char* utf8_message = gpr_format_message(info->wsa_error);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message);
gpr_free(utf8_message);
- grpc_slice_unref_internal(tcp->read_slice);
+ grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
} else {
if (info->bytes_transfered != 0 && !tcp->shutting_down) {
- sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
- grpc_slice_buffer_add(tcp->read_slices, sub);
+ GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length);
+ if (static_cast<size_t>(info->bytes_transfered) !=
+ tcp->read_slices->length) {
+ grpc_slice_buffer_trim_end(
+ tcp->read_slices,
+ tcp->read_slices->length -
+ static_cast<size_t>(info->bytes_transfered),
+ &tcp->last_read_buffer);
+ }
+ GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length);
+
+ if (grpc_tcp_trace.enabled()) {
+ size_t i;
+ for (i = 0; i < tcp->read_slices->count; i++) {
+ char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string,
+ dump);
+ gpr_free(dump);
+ }
+ }
} else {
- grpc_slice_unref_internal(tcp->read_slice);
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp);
+ }
+ grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
error = tcp->shutting_down
? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"TCP stream shutting down", &tcp->shutdown_error, 1)
@@ -209,6 +239,8 @@ static void on_read(void* tcpp, grpc_error* error) {
GRPC_CLOSURE_SCHED(cb, error);
}
+#define DEFAULT_TARGET_READ_SIZE 8192
+#define MAX_WSABUF_COUNT 16
static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
grpc_closure* cb) {
grpc_tcp* tcp = (grpc_tcp*)ep;
@@ -217,7 +249,12 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
int status;
DWORD bytes_read = 0;
DWORD flags = 0;
- WSABUF buffer;
+ WSABUF buffers[MAX_WSABUF_COUNT];
+ size_t i;
+
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP:%p win_read", tcp);
+ }
if (tcp->shutting_down) {
GRPC_CLOSURE_SCHED(
@@ -229,18 +266,27 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
tcp->read_cb = cb;
tcp->read_slices = read_slices;
grpc_slice_buffer_reset_and_unref_internal(read_slices);
+ grpc_slice_buffer_swap(read_slices, &tcp->last_read_buffer);
- tcp->read_slice = GRPC_SLICE_MALLOC(8192);
+ if (tcp->read_slices->length < DEFAULT_TARGET_READ_SIZE / 2 &&
+ tcp->read_slices->count < MAX_WSABUF_COUNT) {
+ // TODO(jtattermusch): slice should be allocated using resource quota
+ grpc_slice_buffer_add(tcp->read_slices,
+ GRPC_SLICE_MALLOC(DEFAULT_TARGET_READ_SIZE));
+ }
- buffer.len = (ULONG)GRPC_SLICE_LENGTH(
- tcp->read_slice); // we know slice size fits in 32bit.
- buffer.buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slice);
+ GPR_ASSERT(tcp->read_slices->count <= MAX_WSABUF_COUNT);
+ for (i = 0; i < tcp->read_slices->count; i++) {
+ buffers[i].len = (ULONG)GRPC_SLICE_LENGTH(
+ tcp->read_slices->slices[i]); // we know slice size fits in 32bit.
+ buffers[i].buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[i]);
+ }
TCP_REF(tcp, "read");
/* 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, buffers, (DWORD)tcp->read_slices->count,
+ &bytes_read, &flags, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
/* Did we get data immediately ? Yay. */
@@ -252,8 +298,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
/* Otherwise, let's retry, by queuing a read. */
memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
- status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
- &info->overlapped, NULL);
+ status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count,
+ &bytes_read, &flags, &info->overlapped, NULL);
if (status != 0) {
int wsa_error = WSAGetLastError();
@@ -275,6 +321,10 @@ static void on_write(void* tcpp, grpc_error* error) {
grpc_winsocket_callback_info* info = &handle->write_info;
grpc_closure* cb;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP:%p on_write", tcp);
+ }
+
GRPC_ERROR_REF(error);
gpr_mu_lock(&tcp->mu);
@@ -303,11 +353,21 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
unsigned i;
DWORD bytes_sent;
int status;
- WSABUF local_buffers[16];
+ WSABUF local_buffers[MAX_WSABUF_COUNT];
WSABUF* allocated = NULL;
WSABUF* buffers = local_buffers;
size_t len;
+ if (grpc_tcp_trace.enabled()) {
+ size_t i;
+ for (i = 0; i < slices->count; i++) {
+ char* data =
+ grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
+ gpr_free(data);
+ }
+ }
+
if (tcp->shutting_down) {
GRPC_CLOSURE_SCHED(
cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
@@ -412,6 +472,7 @@ static void win_shutdown(grpc_endpoint* ep, grpc_error* why) {
static void win_destroy(grpc_endpoint* ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp* tcp = (grpc_tcp*)ep;
+ grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
TCP_UNREF(tcp, "destroy");
}
@@ -427,6 +488,8 @@ static grpc_resource_user* win_get_resource_user(grpc_endpoint* ep) {
static int win_get_fd(grpc_endpoint* ep) { return -1; }
+static bool win_can_track_err(grpc_endpoint* ep) { return false; }
+
static grpc_endpoint_vtable vtable = {win_read,
win_write,
win_add_to_pollset,
@@ -436,7 +499,8 @@ static grpc_endpoint_vtable vtable = {win_read,
win_destroy,
win_get_resource_user,
win_get_peer,
- win_get_fd};
+ win_get_fd,
+ win_can_track_err};
grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket,
grpc_channel_args* channel_args,
@@ -460,6 +524,7 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket,
GRPC_CLOSURE_INIT(&tcp->on_read, on_read, tcp, grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&tcp->on_write, on_write, tcp, grpc_schedule_on_exec_ctx);
tcp->peer_string = gpr_strdup(peer_string);
+ grpc_slice_buffer_init(&tcp->last_read_buffer);
tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
/* Tell network status tracking code about the new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc
index 94c9c69fcd..16f40b4f55 100644
--- a/src/core/lib/security/context/security_context.cc
+++ b/src/core/lib/security/context/security_context.cc
@@ -81,38 +81,45 @@ void grpc_auth_context_release(grpc_auth_context* context) {
}
/* --- grpc_client_security_context --- */
+grpc_client_security_context::~grpc_client_security_context() {
+ grpc_call_credentials_unref(creds);
+ GRPC_AUTH_CONTEXT_UNREF(auth_context, "client_security_context");
+ if (extension.instance != nullptr && extension.destroy != nullptr) {
+ extension.destroy(extension.instance);
+ }
+}
grpc_client_security_context* grpc_client_security_context_create(
gpr_arena* arena) {
- return static_cast<grpc_client_security_context*>(
- gpr_arena_alloc(arena, sizeof(grpc_client_security_context)));
+ return new (gpr_arena_alloc(arena, sizeof(grpc_client_security_context)))
+ grpc_client_security_context();
}
void grpc_client_security_context_destroy(void* ctx) {
grpc_core::ExecCtx exec_ctx;
grpc_client_security_context* c =
static_cast<grpc_client_security_context*>(ctx);
- grpc_call_credentials_unref(c->creds);
- GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
- if (c->extension.instance != nullptr && c->extension.destroy != nullptr) {
- c->extension.destroy(c->extension.instance);
- }
+ c->~grpc_client_security_context();
}
/* --- grpc_server_security_context --- */
+grpc_server_security_context::~grpc_server_security_context() {
+ GRPC_AUTH_CONTEXT_UNREF(auth_context, "server_security_context");
+ if (extension.instance != nullptr && extension.destroy != nullptr) {
+ extension.destroy(extension.instance);
+ }
+}
+
grpc_server_security_context* grpc_server_security_context_create(
gpr_arena* arena) {
- return static_cast<grpc_server_security_context*>(
- gpr_arena_alloc(arena, sizeof(grpc_server_security_context)));
+ return new (gpr_arena_alloc(arena, sizeof(grpc_server_security_context)))
+ grpc_server_security_context();
}
void grpc_server_security_context_destroy(void* ctx) {
grpc_server_security_context* c =
static_cast<grpc_server_security_context*>(ctx);
- GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context");
- if (c->extension.instance != nullptr && c->extension.destroy != nullptr) {
- c->extension.destroy(c->extension.instance);
- }
+ c->~grpc_server_security_context();
}
/* --- grpc_auth_context --- */
diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h
index a8e1c3fd64..e45415f63b 100644
--- a/src/core/lib/security/context/security_context.h
+++ b/src/core/lib/security/context/security_context.h
@@ -34,18 +34,20 @@ struct gpr_arena;
/* Property names are always NULL terminated. */
-typedef struct {
- grpc_auth_property* array;
- size_t count;
- size_t capacity;
-} grpc_auth_property_array;
+struct grpc_auth_property_array {
+ grpc_auth_property* array = nullptr;
+ size_t count = 0;
+ size_t capacity = 0;
+};
struct grpc_auth_context {
- struct grpc_auth_context* chained;
+ grpc_auth_context() { gpr_ref_init(&refcount, 0); }
+
+ struct grpc_auth_context* chained = nullptr;
grpc_auth_property_array properties;
gpr_refcount refcount;
- const char* peer_identity_property_name;
- grpc_pollset* pollset;
+ const char* peer_identity_property_name = nullptr;
+ grpc_pollset* pollset = nullptr;
};
/* Creation. */
@@ -76,20 +78,23 @@ void grpc_auth_property_reset(grpc_auth_property* property);
Extension to the security context that may be set in a filter and accessed
later by a higher level method on a grpc_call object. */
-typedef struct {
- void* instance;
- void (*destroy)(void*);
-} grpc_security_context_extension;
+struct grpc_security_context_extension {
+ void* instance = nullptr;
+ void (*destroy)(void*) = nullptr;
+};
/* --- grpc_client_security_context ---
Internal client-side security context. */
-typedef struct {
- grpc_call_credentials* creds;
- grpc_auth_context* auth_context;
+struct grpc_client_security_context {
+ grpc_client_security_context() = default;
+ ~grpc_client_security_context();
+
+ grpc_call_credentials* creds = nullptr;
+ grpc_auth_context* auth_context = nullptr;
grpc_security_context_extension extension;
-} grpc_client_security_context;
+};
grpc_client_security_context* grpc_client_security_context_create(
gpr_arena* arena);
@@ -99,10 +104,13 @@ void grpc_client_security_context_destroy(void* ctx);
Internal server-side security context. */
-typedef struct {
- grpc_auth_context* auth_context;
+struct grpc_server_security_context {
+ grpc_server_security_context() = default;
+ ~grpc_server_security_context();
+
+ grpc_auth_context* auth_context = nullptr;
grpc_security_context_extension extension;
-} grpc_server_security_context;
+};
grpc_server_security_context* grpc_server_security_context_create(
gpr_arena* arena);
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index b486d25ab2..3878958b38 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -142,8 +142,8 @@ grpc_channel_credentials* grpc_channel_credentials_find_in_args(
/* --- grpc_credentials_mdelem_array. --- */
typedef struct {
- grpc_mdelem* md;
- size_t size;
+ grpc_mdelem* md = nullptr;
+ size_t size = 0;
} grpc_credentials_mdelem_array;
/// Takes a new ref to \a md.
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
index c456ffaf5d..0674540d01 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
@@ -49,9 +49,16 @@
/* -- Default credentials. -- */
-static grpc_channel_credentials* g_default_credentials = nullptr;
-static int g_compute_engine_detection_done = 0;
+/* A sticky bit that will be set only if the result of metadata server detection
+ * is positive. We do not set the bit if the result is negative. Because it
+ * means the detection is done via network test that is unreliable and the
+ * unreliable result should not be referred by successive calls. */
+static int g_metadata_server_available = 0;
+static int g_is_on_gce = 0;
static gpr_mu g_state_mu;
+/* Protect a metadata_server_detector instance that can be modified by more than
+ * one gRPC threads */
+static gpr_mu* g_polling_mu;
static gpr_once g_once = GPR_ONCE_INIT;
static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
grpc_alts_is_running_on_gcp;
@@ -63,7 +70,7 @@ typedef struct {
int is_done;
int success;
grpc_http_response response;
-} compute_engine_detector;
+} metadata_server_detector;
static void google_default_credentials_destruct(
grpc_channel_credentials* creds) {
@@ -89,15 +96,21 @@ static grpc_security_status google_default_create_security_connector(
bool use_alts =
is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer;
grpc_security_status status = GRPC_SECURITY_ERROR;
+ /* Return failure if ALTS is selected but not running on GCE. */
+ if (use_alts && !g_is_on_gce) {
+ gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE.");
+ goto end;
+ }
status = use_alts ? c->alts_creds->vtable->create_security_connector(
c->alts_creds, call_creds, target, args, sc, new_args)
: c->ssl_creds->vtable->create_security_connector(
c->ssl_creds, call_creds, target, args, sc, new_args);
- /* grpclb-specific channel args are removed from the channel args set
- * to ensure backends and fallback adresses will have the same set of channel
- * args. By doing that, it guarantees the connections to backends will not be
- * torn down and re-connected when switching in and out of fallback mode.
- */
+/* grpclb-specific channel args are removed from the channel args set
+ * to ensure backends and fallback adresses will have the same set of channel
+ * args. By doing that, it guarantees the connections to backends will not be
+ * torn down and re-connected when switching in and out of fallback mode.
+ */
+end:
if (use_alts) {
static const char* args_to_remove[] = {
GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER,
@@ -113,6 +126,93 @@ static grpc_channel_credentials_vtable google_default_credentials_vtable = {
google_default_credentials_destruct,
google_default_create_security_connector, nullptr};
+static void on_metadata_server_detection_http_response(void* user_data,
+ grpc_error* error) {
+ metadata_server_detector* detector =
+ static_cast<metadata_server_detector*>(user_data);
+ if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
+ detector->response.hdr_count > 0) {
+ /* Internet providers can return a generic response to all requests, so
+ it is necessary to check that metadata header is present also. */
+ size_t i;
+ for (i = 0; i < detector->response.hdr_count; i++) {
+ grpc_http_header* header = &detector->response.hdrs[i];
+ if (strcmp(header->key, "Metadata-Flavor") == 0 &&
+ strcmp(header->value, "Google") == 0) {
+ detector->success = 1;
+ break;
+ }
+ }
+ }
+ gpr_mu_lock(g_polling_mu);
+ detector->is_done = 1;
+ GRPC_LOG_IF_ERROR(
+ "Pollset kick",
+ grpc_pollset_kick(grpc_polling_entity_pollset(&detector->pollent),
+ nullptr));
+ gpr_mu_unlock(g_polling_mu);
+}
+
+static void destroy_pollset(void* p, grpc_error* e) {
+ grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
+}
+
+static int is_metadata_server_reachable() {
+ metadata_server_detector detector;
+ grpc_httpcli_request request;
+ grpc_httpcli_context context;
+ grpc_closure destroy_closure;
+ /* The http call is local. If it takes more than one sec, it is for sure not
+ on compute engine. */
+ grpc_millis max_detection_delay = GPR_MS_PER_SEC;
+ grpc_pollset* pollset =
+ static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
+ grpc_pollset_init(pollset, &g_polling_mu);
+ detector.pollent = grpc_polling_entity_create_from_pollset(pollset);
+ detector.is_done = 0;
+ detector.success = 0;
+ memset(&detector.response, 0, sizeof(detector.response));
+ memset(&request, 0, sizeof(grpc_httpcli_request));
+ request.host = (char*)GRPC_COMPUTE_ENGINE_DETECTION_HOST;
+ request.http.path = (char*)"/";
+ grpc_httpcli_context_init(&context);
+ grpc_resource_quota* resource_quota =
+ grpc_resource_quota_create("google_default_credentials");
+ grpc_httpcli_get(
+ &context, &detector.pollent, resource_quota, &request,
+ grpc_core::ExecCtx::Get()->Now() + max_detection_delay,
+ GRPC_CLOSURE_CREATE(on_metadata_server_detection_http_response, &detector,
+ grpc_schedule_on_exec_ctx),
+ &detector.response);
+ grpc_resource_quota_unref_internal(resource_quota);
+ grpc_core::ExecCtx::Get()->Flush();
+ /* Block until we get the response. This is not ideal but this should only be
+ called once for the lifetime of the process by the default credentials. */
+ gpr_mu_lock(g_polling_mu);
+ while (!detector.is_done) {
+ grpc_pollset_worker* worker = nullptr;
+ if (!GRPC_LOG_IF_ERROR(
+ "pollset_work",
+ grpc_pollset_work(grpc_polling_entity_pollset(&detector.pollent),
+ &worker, GRPC_MILLIS_INF_FUTURE))) {
+ detector.is_done = 1;
+ detector.success = 0;
+ }
+ }
+ gpr_mu_unlock(g_polling_mu);
+ grpc_httpcli_context_destroy(&context);
+ GRPC_CLOSURE_INIT(&destroy_closure, destroy_pollset,
+ grpc_polling_entity_pollset(&detector.pollent),
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(grpc_polling_entity_pollset(&detector.pollent),
+ &destroy_closure);
+ g_polling_mu = nullptr;
+ grpc_core::ExecCtx::Get()->Flush();
+ gpr_free(grpc_polling_entity_pollset(&detector.pollent));
+ grpc_http_response_destroy(&detector.response);
+ return detector.success;
+}
+
/* Takes ownership of creds_path if not NULL. */
static grpc_error* create_default_creds_from_path(
char* creds_path, grpc_call_credentials** creds) {
@@ -188,13 +288,6 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
gpr_once_init(&g_once, init_default_credentials);
- gpr_mu_lock(&g_state_mu);
-
- if (g_default_credentials != nullptr) {
- result = grpc_channel_credentials_ref(g_default_credentials);
- goto end;
- }
-
/* First, try the environment variable. */
err = create_default_creds_from_path(
gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
@@ -207,55 +300,55 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
if (err == GRPC_ERROR_NONE) goto end;
error = grpc_error_add_child(error, err);
- /* At last try to see if we're on compute engine (do the detection only once
- since it requires a network test). */
- if (!g_compute_engine_detection_done) {
- int need_compute_engine_creds = g_gce_tenancy_checker();
- g_compute_engine_detection_done = 1;
- if (need_compute_engine_creds) {
- call_creds = grpc_google_compute_engine_credentials_create(nullptr);
- if (call_creds == nullptr) {
- error = grpc_error_add_child(
- error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to get credentials from network"));
- }
- }
+ gpr_mu_lock(&g_state_mu);
+
+ /* Try a platform-provided hint for GCE. */
+ if (!g_metadata_server_available) {
+ g_is_on_gce = g_gce_tenancy_checker();
+ g_metadata_server_available = g_is_on_gce;
}
+ /* TODO: Add a platform-provided hint for GAE. */
-end:
- if (result == nullptr) {
- if (call_creds != nullptr) {
- /* Create google default credentials. */
- auto creds = static_cast<grpc_google_default_channel_credentials*>(
- gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
- creds->base.vtable = &google_default_credentials_vtable;
- creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
- gpr_ref_init(&creds->base.refcount, 1);
- creds->ssl_creds =
- grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
- GPR_ASSERT(creds->ssl_creds != nullptr);
- grpc_alts_credentials_options* options =
- grpc_alts_credentials_client_options_create();
- creds->alts_creds = grpc_alts_credentials_create(options);
- grpc_alts_credentials_options_destroy(options);
- /* Add a global reference so that it can be cached and re-served. */
- g_default_credentials = grpc_composite_channel_credentials_create(
- &creds->base, call_creds, nullptr);
- GPR_ASSERT(g_default_credentials != nullptr);
- grpc_channel_credentials_unref(&creds->base);
- grpc_call_credentials_unref(call_creds);
- result = grpc_channel_credentials_ref(g_default_credentials);
- } else {
- gpr_log(GPR_ERROR, "Could not create google default credentials.");
- }
+ /* Do a network test for metadata server. */
+ if (!g_metadata_server_available) {
+ g_metadata_server_available = is_metadata_server_reachable();
}
gpr_mu_unlock(&g_state_mu);
- if (result == nullptr) {
- GRPC_LOG_IF_ERROR("grpc_google_default_credentials_create", error);
- } else {
- GRPC_ERROR_UNREF(error);
+
+ if (g_metadata_server_available) {
+ call_creds = grpc_google_compute_engine_credentials_create(nullptr);
+ if (call_creds == nullptr) {
+ error = grpc_error_add_child(
+ error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Failed to get credentials from network"));
+ }
}
+end:
+ if (call_creds != nullptr) {
+ /* Create google default credentials. */
+ auto creds = static_cast<grpc_google_default_channel_credentials*>(
+ gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
+ creds->base.vtable = &google_default_credentials_vtable;
+ creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
+ gpr_ref_init(&creds->base.refcount, 1);
+ creds->ssl_creds =
+ grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
+ GPR_ASSERT(creds->ssl_creds != nullptr);
+ grpc_alts_credentials_options* options =
+ grpc_alts_credentials_client_options_create();
+ creds->alts_creds = grpc_alts_credentials_create(options);
+ grpc_alts_credentials_options_destroy(options);
+ result = grpc_composite_channel_credentials_create(&creds->base, call_creds,
+ nullptr);
+ GPR_ASSERT(result != nullptr);
+ grpc_channel_credentials_unref(&creds->base);
+ grpc_call_credentials_unref(call_creds);
+ } else {
+ gpr_log(GPR_ERROR, "Could not create google default credentials: %s",
+ grpc_error_string(error));
+ }
+ GRPC_ERROR_UNREF(error);
return result;
}
@@ -266,21 +359,17 @@ void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker) {
g_gce_tenancy_checker = checker;
}
-} // namespace internal
-} // namespace grpc_core
-
void grpc_flush_cached_google_default_credentials(void) {
grpc_core::ExecCtx exec_ctx;
gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_state_mu);
- if (g_default_credentials != nullptr) {
- grpc_channel_credentials_unref(g_default_credentials);
- g_default_credentials = nullptr;
- }
- g_compute_engine_detection_done = 0;
+ g_metadata_server_available = 0;
gpr_mu_unlock(&g_state_mu);
}
+} // namespace internal
+} // namespace grpc_core
+
/* -- Well known credentials path. -- */
static grpc_well_known_credentials_path_getter creds_path_getter = nullptr;
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.h b/src/core/lib/security/credentials/google_default/google_default_credentials.h
index a7dd0ea8ae..b9e2efb04f 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.h
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.h
@@ -45,8 +45,6 @@ typedef struct {
grpc_channel_credentials* ssl_creds;
} grpc_google_default_channel_credentials;
-void grpc_flush_cached_google_default_credentials(void);
-
namespace grpc_core {
namespace internal {
@@ -54,6 +52,9 @@ typedef bool (*grpc_gce_tenancy_checker)(void);
void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker);
+// TEST-ONLY. Reset the internal global state.
+void grpc_flush_cached_google_default_credentials(void);
+
} // namespace internal
} // namespace grpc_core
diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc
index e34eacc8d7..6955e8698e 100644
--- a/src/core/lib/security/transport/client_auth_filter.cc
+++ b/src/core/lib/security/transport/client_auth_filter.cc
@@ -43,20 +43,39 @@
namespace {
/* We can have a per-call credentials. */
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : arena(args.arena),
+ owning_call(args.call_stack),
+ call_combiner(args.call_combiner) {}
+
+ // This method is technically the dtor of this class. However, since
+ // `get_request_metadata_cancel_closure` can run in parallel to
+ // `destroy_call_elem`, we cannot call the dtor in them. Otherwise,
+ // fields will be accessed after calling dtor, and msan correctly complains
+ // that the memory is not initialized.
+ void destroy() {
+ grpc_credentials_mdelem_array_destroy(&md_array);
+ grpc_call_credentials_unref(creds);
+ grpc_slice_unref_internal(host);
+ grpc_slice_unref_internal(method);
+ grpc_auth_metadata_context_reset(&auth_md_context);
+ }
+
gpr_arena* arena;
grpc_call_stack* owning_call;
grpc_call_combiner* call_combiner;
- grpc_call_credentials* creds;
- grpc_slice host;
- grpc_slice method;
+ grpc_call_credentials* creds = nullptr;
+ grpc_slice host = grpc_empty_slice();
+ grpc_slice method = grpc_empty_slice();
/* pollset{_set} bound to this call; if we need to make external
network requests, they should be done under a pollset added to this
pollset_set so that work can progress when this call wants work to progress
*/
- grpc_polling_entity* pollent;
+ grpc_polling_entity* pollent = nullptr;
grpc_credentials_mdelem_array md_array;
- grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
- grpc_auth_metadata_context auth_md_context;
+ grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT] = {};
+ grpc_auth_metadata_context auth_md_context =
+ grpc_auth_metadata_context(); // Zero-initialize the C struct.
grpc_closure async_result_closure;
grpc_closure check_call_host_cancel_closure;
grpc_closure get_request_metadata_cancel_closure;
@@ -334,12 +353,7 @@ static void auth_start_transport_stream_op_batch(
/* Constructor for call_data */
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- calld->arena = args->arena;
- calld->owning_call = args->call_stack;
- calld->call_combiner = args->call_combiner;
- calld->host = grpc_empty_slice();
- calld->method = grpc_empty_slice();
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -354,11 +368,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- grpc_credentials_mdelem_array_destroy(&calld->md_array);
- grpc_call_credentials_unref(calld->creds);
- grpc_slice_unref_internal(calld->host);
- grpc_slice_unref_internal(calld->method);
- grpc_auth_metadata_context_reset(&calld->auth_md_context);
+ calld->destroy();
}
/* Constructor for channel_data */
diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc
index f40f969bb7..14fb55884f 100644
--- a/src/core/lib/security/transport/secure_endpoint.cc
+++ b/src/core/lib/security/transport/secure_endpoint.cc
@@ -22,6 +22,8 @@
headers. Therefore, sockaddr.h must always be included first */
#include <grpc/support/port_platform.h>
+#include <new>
+
#include "src/core/lib/iomgr/sockaddr.h"
#include <grpc/slice.h>
@@ -31,6 +33,7 @@
#include <grpc/support/sync.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/tsi_error.h"
@@ -40,44 +43,68 @@
#define STAGING_BUFFER_SIZE 8192
-typedef struct {
+static void on_read(void* user_data, grpc_error* error);
+
+namespace {
+struct secure_endpoint {
+ secure_endpoint(const grpc_endpoint_vtable* vtable,
+ tsi_frame_protector* protector,
+ tsi_zero_copy_grpc_protector* zero_copy_protector,
+ grpc_endpoint* transport, grpc_slice* leftover_slices,
+ size_t leftover_nslices)
+ : wrapped_ep(transport),
+ protector(protector),
+ zero_copy_protector(zero_copy_protector) {
+ base.vtable = vtable;
+ gpr_mu_init(&protector_mu);
+ GRPC_CLOSURE_INIT(&on_read, ::on_read, this, grpc_schedule_on_exec_ctx);
+ grpc_slice_buffer_init(&source_buffer);
+ grpc_slice_buffer_init(&leftover_bytes);
+ for (size_t i = 0; i < leftover_nslices; i++) {
+ grpc_slice_buffer_add(&leftover_bytes,
+ grpc_slice_ref_internal(leftover_slices[i]));
+ }
+ grpc_slice_buffer_init(&output_buffer);
+ gpr_ref_init(&ref, 1);
+ }
+
+ ~secure_endpoint() {
+ grpc_endpoint_destroy(wrapped_ep);
+ tsi_frame_protector_destroy(protector);
+ tsi_zero_copy_grpc_protector_destroy(zero_copy_protector);
+ grpc_slice_buffer_destroy_internal(&source_buffer);
+ grpc_slice_buffer_destroy_internal(&leftover_bytes);
+ grpc_slice_unref_internal(read_staging_buffer);
+ grpc_slice_unref_internal(write_staging_buffer);
+ grpc_slice_buffer_destroy_internal(&output_buffer);
+ gpr_mu_destroy(&protector_mu);
+ }
+
grpc_endpoint base;
grpc_endpoint* wrapped_ep;
struct tsi_frame_protector* protector;
struct tsi_zero_copy_grpc_protector* zero_copy_protector;
gpr_mu protector_mu;
/* saved upper level callbacks and user_data. */
- grpc_closure* read_cb;
- grpc_closure* write_cb;
+ grpc_closure* read_cb = nullptr;
+ grpc_closure* write_cb = nullptr;
grpc_closure on_read;
- grpc_slice_buffer* read_buffer;
+ grpc_slice_buffer* read_buffer = nullptr;
grpc_slice_buffer source_buffer;
/* saved handshaker leftover data to unprotect. */
grpc_slice_buffer leftover_bytes;
/* buffers for read and write */
- grpc_slice read_staging_buffer;
-
- grpc_slice write_staging_buffer;
+ grpc_slice read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE);
+ grpc_slice write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE);
grpc_slice_buffer output_buffer;
gpr_refcount ref;
-} secure_endpoint;
+};
+} // namespace
grpc_core::TraceFlag grpc_trace_secure_endpoint(false, "secure_endpoint");
-static void destroy(secure_endpoint* secure_ep) {
- secure_endpoint* ep = secure_ep;
- grpc_endpoint_destroy(ep->wrapped_ep);
- tsi_frame_protector_destroy(ep->protector);
- tsi_zero_copy_grpc_protector_destroy(ep->zero_copy_protector);
- grpc_slice_buffer_destroy_internal(&ep->leftover_bytes);
- grpc_slice_unref_internal(ep->read_staging_buffer);
- grpc_slice_unref_internal(ep->write_staging_buffer);
- grpc_slice_buffer_destroy_internal(&ep->output_buffer);
- grpc_slice_buffer_destroy_internal(&ep->source_buffer);
- gpr_mu_destroy(&ep->protector_mu);
- gpr_free(ep);
-}
+static void destroy(secure_endpoint* ep) { grpc_core::Delete(ep); }
#ifndef NDEBUG
#define SECURE_ENDPOINT_UNREF(ep, reason) \
@@ -389,6 +416,11 @@ static grpc_resource_user* endpoint_get_resource_user(
return grpc_endpoint_get_resource_user(ep->wrapped_ep);
}
+static bool endpoint_can_track_err(grpc_endpoint* secure_ep) {
+ secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
+ return grpc_endpoint_can_track_err(ep->wrapped_ep);
+}
+
static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_write,
endpoint_add_to_pollset,
@@ -398,32 +430,16 @@ static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_destroy,
endpoint_get_resource_user,
endpoint_get_peer,
- endpoint_get_fd};
+ endpoint_get_fd,
+ endpoint_can_track_err};
grpc_endpoint* grpc_secure_endpoint_create(
struct tsi_frame_protector* protector,
struct tsi_zero_copy_grpc_protector* zero_copy_protector,
grpc_endpoint* transport, grpc_slice* leftover_slices,
size_t leftover_nslices) {
- size_t i;
- secure_endpoint* ep =
- static_cast<secure_endpoint*>(gpr_malloc(sizeof(secure_endpoint)));
- ep->base.vtable = &vtable;
- ep->wrapped_ep = transport;
- ep->protector = protector;
- ep->zero_copy_protector = zero_copy_protector;
- grpc_slice_buffer_init(&ep->leftover_bytes);
- for (i = 0; i < leftover_nslices; i++) {
- grpc_slice_buffer_add(&ep->leftover_bytes,
- grpc_slice_ref_internal(leftover_slices[i]));
- }
- ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE);
- ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE);
- grpc_slice_buffer_init(&ep->output_buffer);
- grpc_slice_buffer_init(&ep->source_buffer);
- ep->read_buffer = nullptr;
- GRPC_CLOSURE_INIT(&ep->on_read, on_read, ep, grpc_schedule_on_exec_ctx);
- gpr_mu_init(&ep->protector_mu);
- gpr_ref_init(&ep->ref, 1);
+ secure_endpoint* ep = grpc_core::New<secure_endpoint>(
+ &vtable, protector, zero_copy_protector, transport, leftover_slices,
+ leftover_nslices);
return &ep->base;
}
diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc
index 4d6b133809..854a1c4af9 100644
--- a/src/core/lib/security/transport/security_handshaker.cc
+++ b/src/core/lib/security/transport/security_handshaker.cc
@@ -275,9 +275,6 @@ static void on_handshake_next_done_grpc_wrapper(
tsi_result result, void* user_data, const unsigned char* bytes_to_send,
size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
security_handshaker* h = static_cast<security_handshaker*>(user_data);
- // This callback will be invoked by TSI in a non-grpc thread, so it's
- // safe to create our own exec_ctx here.
- grpc_core::ExecCtx exec_ctx;
gpr_mu_lock(&h->mu);
grpc_error* error = on_handshake_next_done_locked(
h, result, bytes_to_send, bytes_to_send_size, handshaker_result);
diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc
index b99fc5e178..362f49a584 100644
--- a/src/core/lib/security/transport/server_auth_filter.cc
+++ b/src/core/lib/security/transport/server_auth_filter.cc
@@ -28,6 +28,9 @@
#include "src/core/lib/security/transport/auth_filters.h"
#include "src/core/lib/slice/slice_internal.h"
+static void recv_initial_metadata_ready(void* arg, grpc_error* error);
+static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+
namespace {
enum async_state {
STATE_INIT = 0,
@@ -35,28 +38,55 @@ enum async_state {
STATE_CANCELLED,
};
+struct channel_data {
+ grpc_auth_context* auth_context;
+ grpc_server_credentials* creds;
+};
+
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call_combiner(args.call_combiner), owning_call(args.call_stack) {
+ GRPC_CLOSURE_INIT(&recv_initial_metadata_ready,
+ ::recv_initial_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ ::recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ // Create server security context. Set its auth context from channel
+ // data and save it in the call context.
+ grpc_server_security_context* server_ctx =
+ grpc_server_security_context_create(args.arena);
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ server_ctx->auth_context =
+ GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter");
+ if (args.context[GRPC_CONTEXT_SECURITY].value != nullptr) {
+ args.context[GRPC_CONTEXT_SECURITY].destroy(
+ args.context[GRPC_CONTEXT_SECURITY].value);
+ }
+ args.context[GRPC_CONTEXT_SECURITY].value = server_ctx;
+ args.context[GRPC_CONTEXT_SECURITY].destroy =
+ grpc_server_security_context_destroy;
+ }
+
+ ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); }
+
grpc_call_combiner* call_combiner;
grpc_call_stack* owning_call;
grpc_transport_stream_op_batch* recv_initial_metadata_batch;
grpc_closure* original_recv_initial_metadata_ready;
grpc_closure recv_initial_metadata_ready;
- grpc_error* recv_initial_metadata_error;
+ grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
grpc_closure recv_trailing_metadata_ready;
grpc_closure* original_recv_trailing_metadata_ready;
grpc_error* recv_trailing_metadata_error;
- bool seen_recv_trailing_metadata_ready;
+ bool seen_recv_trailing_metadata_ready = false;
grpc_metadata_array md;
const grpc_metadata* consumed_md;
size_t num_consumed_md;
grpc_closure cancel_closure;
- gpr_atm state; // async_state
+ gpr_atm state = STATE_INIT; // async_state
};
-struct channel_data {
- grpc_auth_context* auth_context;
- grpc_server_credentials* creds;
-};
} // namespace
static grpc_metadata_array metadata_batch_to_md_array(
@@ -244,29 +274,7 @@ static void auth_start_transport_stream_op_batch(
/* Constructor for call_data */
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- calld->call_combiner = args->call_combiner;
- calld->owning_call = args->call_stack;
- GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
- recv_initial_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
- recv_trailing_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
- // Create server security context. Set its auth context from channel
- // data and save it in the call context.
- grpc_server_security_context* server_ctx =
- grpc_server_security_context_create(args->arena);
- server_ctx->auth_context =
- GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter");
- if (args->context[GRPC_CONTEXT_SECURITY].value != nullptr) {
- args->context[GRPC_CONTEXT_SECURITY].destroy(
- args->context[GRPC_CONTEXT_SECURITY].value);
- }
- args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
- args->context[GRPC_CONTEXT_SECURITY].destroy =
- grpc_server_security_context_destroy;
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -275,7 +283,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- GRPC_ERROR_UNREF(calld->recv_initial_metadata_error);
+ calld->~call_data();
}
/* Constructor for channel_data */
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index a9349afa68..89b3f77822 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -72,8 +72,11 @@
// Used to create arena for the first call.
#define ESTIMATED_MDELEM_COUNT 16
-typedef struct batch_control {
- grpc_call* call;
+struct batch_control {
+ batch_control() { gpr_ref_init(&steps_to_complete, 0); }
+
+ grpc_call* call = nullptr;
+ grpc_transport_stream_op_batch op;
/* Share memory for cq_completion and notify_tag as they are never needed
simultaneously. Each byte used in this data structure count as six bytes
per call, so any savings we can make are worthwhile,
@@ -96,84 +99,110 @@ typedef struct batch_control {
grpc_closure start_batch;
grpc_closure finish_batch;
gpr_refcount steps_to_complete;
- gpr_atm batch_error;
- grpc_transport_stream_op_batch op;
-} batch_control;
+ gpr_atm batch_error = reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE);
+};
+
+struct parent_call {
+ parent_call() { gpr_mu_init(&child_list_mu); }
+ ~parent_call() { gpr_mu_destroy(&child_list_mu); }
-typedef struct {
gpr_mu child_list_mu;
- grpc_call* first_child;
-} parent_call;
+ grpc_call* first_child = nullptr;
+};
-typedef struct {
+struct child_call {
+ child_call(grpc_call* parent) : parent(parent) {}
grpc_call* parent;
/** 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;
-} child_call;
+ grpc_call* sibling_next = nullptr;
+ grpc_call* sibling_prev = nullptr;
+};
#define RECV_NONE ((gpr_atm)0)
#define RECV_INITIAL_METADATA_FIRST ((gpr_atm)1)
struct grpc_call {
+ grpc_call(gpr_arena* arena, const grpc_call_create_args& args)
+ : arena(arena),
+ cq(args.cq),
+ channel(args.channel),
+ is_client(args.server_transport_data == nullptr),
+ stream_op_payload(context) {
+ gpr_ref_init(&ext_ref, 1);
+ grpc_call_combiner_init(&call_combiner);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE;
+ }
+ }
+ }
+
+ ~grpc_call() {
+ gpr_free(static_cast<void*>(const_cast<char*>(final_info.error_string)));
+ grpc_call_combiner_destroy(&call_combiner);
+ }
+
gpr_refcount ext_ref;
gpr_arena* arena;
grpc_call_combiner call_combiner;
grpc_completion_queue* cq;
grpc_polling_entity pollent;
grpc_channel* channel;
- gpr_timespec start_time;
- /* parent_call* */ gpr_atm parent_call_atm;
- child_call* child;
+ gpr_timespec start_time = gpr_now(GPR_CLOCK_MONOTONIC);
+ /* parent_call* */ gpr_atm parent_call_atm = 0;
+ child_call* child = nullptr;
/* client or server call */
bool is_client;
/** has grpc_call_unref been called */
- bool destroy_called;
+ bool destroy_called = false;
/** flag indicating that cancellation is inherited */
- bool cancellation_is_inherited;
+ bool cancellation_is_inherited = false;
/** which ops are in-flight */
- bool sent_initial_metadata;
- bool sending_message;
- bool sent_final_op;
- bool received_initial_metadata;
- bool receiving_message;
- bool requested_final_op;
- gpr_atm any_ops_sent_atm;
- gpr_atm received_final_op_atm;
-
- batch_control* active_batches[MAX_CONCURRENT_BATCHES];
+ bool sent_initial_metadata = false;
+ bool sending_message = false;
+ bool sent_final_op = false;
+ bool received_initial_metadata = false;
+ bool receiving_message = false;
+ bool requested_final_op = false;
+ gpr_atm any_ops_sent_atm = 0;
+ gpr_atm received_final_op_atm = 0;
+
+ batch_control* active_batches[MAX_CONCURRENT_BATCHES] = {};
grpc_transport_stream_op_batch_payload stream_op_payload;
/* first idx: is_receiving, second idx: is_trailing */
- grpc_metadata_batch metadata_batch[2][2];
+ grpc_metadata_batch metadata_batch[2][2] = {};
/* Buffered read metadata waiting to be returned to the application.
Element 0 is initial metadata, element 1 is trailing metadata. */
- grpc_metadata_array* buffered_metadata[2];
+ grpc_metadata_array* buffered_metadata[2] = {};
grpc_metadata compression_md;
// A char* indicating the peer name.
- gpr_atm peer_string;
+ gpr_atm peer_string = 0;
/* Call data useful used for reporting. Only valid after the call has
* completed */
grpc_call_final_info final_info;
/* Compression algorithm for *incoming* data */
- grpc_message_compression_algorithm incoming_message_compression_algorithm;
+ grpc_message_compression_algorithm incoming_message_compression_algorithm =
+ GRPC_MESSAGE_COMPRESS_NONE;
/* Stream compression algorithm for *incoming* data */
- grpc_stream_compression_algorithm incoming_stream_compression_algorithm;
- /* Supported encodings (compression algorithms), a bitset */
- uint32_t encodings_accepted_by_peer;
+ grpc_stream_compression_algorithm incoming_stream_compression_algorithm =
+ GRPC_STREAM_COMPRESS_NONE;
+ /* Supported encodings (compression algorithms), a bitset.
+ * Always support no compression. */
+ uint32_t encodings_accepted_by_peer = 1 << GRPC_MESSAGE_COMPRESS_NONE;
/* Supported stream encodings (stream compression algorithms), a bitset */
- uint32_t stream_encodings_accepted_by_peer;
+ uint32_t stream_encodings_accepted_by_peer = 0;
/* Contexts for various subsystems (security, tracing, ...). */
- grpc_call_context_element context[GRPC_CONTEXT_COUNT];
+ grpc_call_context_element context[GRPC_CONTEXT_COUNT] = {};
/* for the client, extra metadata is initial metadata; for the
server, it's trailing metadata */
@@ -184,14 +213,14 @@ struct grpc_call {
grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sending_stream;
grpc_core::OrphanablePtr<grpc_core::ByteStream> receiving_stream;
- grpc_byte_buffer** receiving_buffer;
- grpc_slice receiving_slice;
+ grpc_byte_buffer** receiving_buffer = nullptr;
+ grpc_slice receiving_slice = grpc_empty_slice();
grpc_closure receiving_slice_ready;
grpc_closure receiving_stream_ready;
grpc_closure receiving_initial_metadata_ready;
grpc_closure receiving_trailing_metadata_ready;
- uint32_t test_only_last_message_flags;
- gpr_atm cancelled;
+ uint32_t test_only_last_message_flags = 0;
+ gpr_atm cancelled = 0;
grpc_closure release_call;
@@ -207,7 +236,7 @@ struct grpc_call {
grpc_server* server;
} server;
} final_op;
- gpr_atm status_error;
+ gpr_atm status_error = 0;
/* recv_state can contain one of the following values:
RECV_NONE : : no initial metadata and messages received
@@ -225,7 +254,7 @@ struct grpc_call {
For 1, 4: See receiving_initial_metadata_ready() function
For 2, 3: See receiving_stream_ready() function */
- gpr_atm recv_state;
+ gpr_atm recv_state = 0;
};
grpc_core::TraceFlag grpc_call_error_trace(false, "call_error");
@@ -269,11 +298,10 @@ void* grpc_call_arena_alloc(grpc_call* call, size_t size) {
static parent_call* get_or_create_parent_call(grpc_call* call) {
parent_call* p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm);
if (p == nullptr) {
- p = static_cast<parent_call*>(gpr_arena_alloc(call->arena, sizeof(*p)));
- gpr_mu_init(&p->child_list_mu);
+ p = new (gpr_arena_alloc(call->arena, sizeof(*p))) parent_call();
if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm) nullptr,
(gpr_atm)p)) {
- gpr_mu_destroy(&p->child_list_mu);
+ p->~parent_call();
p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm);
}
}
@@ -292,7 +320,9 @@ size_t grpc_call_get_initial_size_estimate() {
grpc_error* grpc_call_create(const grpc_call_create_args* args,
grpc_call** out_call) {
GPR_TIMER_SCOPE("grpc_call_create", 0);
- size_t i, j;
+
+ GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
+
grpc_error* error = GRPC_ERROR_NONE;
grpc_channel_stack* channel_stack =
grpc_channel_get_channel_stack(args->channel);
@@ -300,27 +330,19 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
gpr_arena* arena = gpr_arena_create(initial_size);
- call = static_cast<grpc_call*>(
- gpr_arena_alloc(arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
- channel_stack->call_stack_size));
- gpr_ref_init(&call->ext_ref, 1);
- gpr_atm_no_barrier_store(&call->cancelled, 0);
- call->arena = arena;
- grpc_call_combiner_init(&call->call_combiner);
+ call = new (gpr_arena_alloc(
+ arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
+ channel_stack->call_stack_size)) grpc_call(arena, *args);
*out_call = call;
- call->channel = args->channel;
- call->cq = args->cq;
- call->start_time = gpr_now(GPR_CLOCK_MONOTONIC);
- /* Always support no compression */
- GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_MESSAGE_COMPRESS_NONE);
- call->is_client = args->server_transport_data == nullptr;
- call->stream_op_payload.context = call->context;
grpc_slice path = grpc_empty_slice();
if (call->is_client) {
+ call->final_op.client.status_details = nullptr;
+ call->final_op.client.status = nullptr;
+ call->final_op.client.error_string = nullptr;
GRPC_STATS_INC_CLIENT_CALLS_CREATED();
GPR_ASSERT(args->add_initial_metadata_count <
MAX_SEND_EXTRA_METADATA_COUNT);
- for (i = 0; i < args->add_initial_metadata_count; i++) {
+ for (size_t i = 0; i < args->add_initial_metadata_count; i++) {
call->send_extra_metadata[i].md = args->add_initial_metadata[i];
if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]),
GRPC_MDSTR_PATH)) {
@@ -332,23 +354,18 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
static_cast<int>(args->add_initial_metadata_count);
} else {
GRPC_STATS_INC_SERVER_CALLS_CREATED();
+ call->final_op.server.cancelled = nullptr;
call->final_op.server.server = args->server;
GPR_ASSERT(args->add_initial_metadata_count == 0);
call->send_extra_metadata_count = 0;
}
- for (i = 0; i < 2; i++) {
- for (j = 0; j < 2; j++) {
- call->metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE;
- }
- }
- grpc_millis send_deadline = args->send_deadline;
+ grpc_millis send_deadline = args->send_deadline;
bool immediately_cancel = false;
if (args->parent != nullptr) {
- call->child =
- static_cast<child_call*>(gpr_arena_alloc(arena, sizeof(child_call)));
- call->child->parent = args->parent;
+ call->child = new (gpr_arena_alloc(arena, sizeof(child_call)))
+ child_call(args->parent);
GRPC_CALL_INTERNAL_REF(args->parent, "child");
GPR_ASSERT(call->is_client);
@@ -382,10 +399,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
}
}
}
-
call->send_deadline = send_deadline;
-
- GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
/* initial refcount dropped by grpc_call_unref */
grpc_call_element_args call_args = {CALL_STACK_FROM_CALL(call),
args->server_transport_data,
@@ -413,6 +427,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
}
gpr_mu_unlock(&pc->child_list_mu);
}
+
if (error != GRPC_ERROR_NONE) {
cancel_with_error(call, GRPC_ERROR_REF(error));
}
@@ -487,9 +502,9 @@ void grpc_call_internal_unref(grpc_call* c REF_ARG) {
static void release_call(void* call, grpc_error* error) {
grpc_call* c = static_cast<grpc_call*>(call);
grpc_channel* channel = c->channel;
- gpr_free(static_cast<void*>(const_cast<char*>(c->final_info.error_string)));
- grpc_call_combiner_destroy(&c->call_combiner);
- grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(c->arena));
+ gpr_arena* arena = c->arena;
+ c->~grpc_call();
+ grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(arena));
GRPC_CHANNEL_INTERNAL_UNREF(channel, "call");
}
@@ -505,7 +520,7 @@ static void destroy_call(void* call, grpc_error* error) {
c->receiving_stream.reset();
parent_call* pc = get_parent_call(c);
if (pc != nullptr) {
- gpr_mu_destroy(&pc->child_list_mu);
+ pc->~parent_call();
}
for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md);
@@ -679,6 +694,10 @@ static void cancel_with_error(grpc_call* c, grpc_error* error) {
execute_batch(c, op, &state->start_batch);
}
+void grpc_call_cancel_internal(grpc_call* call) {
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
+}
+
static grpc_error* error_from_status(grpc_status_code status,
const char* description) {
// copying 'description' is needed to ensure the grpc_call_cancel_with_status
@@ -1100,10 +1119,11 @@ static batch_control* reuse_or_allocate_batch_control(grpc_call* call,
if (bctl->call != nullptr) {
return nullptr;
}
- memset(bctl, 0, sizeof(*bctl));
+ bctl->~batch_control();
+ bctl->op = {};
} else {
- bctl = static_cast<batch_control*>(
- gpr_arena_alloc(call->arena, sizeof(batch_control)));
+ bctl = new (gpr_arena_alloc(call->arena, sizeof(batch_control)))
+ batch_control();
*pslot = bctl;
}
bctl->call = call;
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index b34260505a..bd7295fe11 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -81,6 +81,10 @@ grpc_call_error grpc_call_start_batch_and_execute(grpc_call* call,
size_t nops,
grpc_closure* closure);
+/* gRPC core internal version of grpc_call_cancel that does not create
+ * exec_ctx. */
+void grpc_call_cancel_internal(grpc_call* call);
+
/* Given the top call_element, get the call object. */
grpc_call* grpc_call_from_top_element(grpc_call_element* surface_element);
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index d7095c24d4..e47cb4360e 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -39,6 +39,7 @@
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -63,6 +64,7 @@ struct grpc_channel {
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
+ grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
@@ -82,6 +84,8 @@ grpc_channel* grpc_channel_create_with_builder(
char* target = gpr_strdup(grpc_channel_stack_builder_get_target(builder));
grpc_channel_args* args = grpc_channel_args_copy(
grpc_channel_stack_builder_get_channel_arguments(builder));
+ grpc_resource_user* resource_user =
+ grpc_channel_stack_builder_get_resource_user(builder);
grpc_channel* channel;
if (channel_stack_type == GRPC_SERVER_CHANNEL) {
GRPC_STATS_INC_SERVER_CHANNELS_CREATED();
@@ -101,9 +105,11 @@ grpc_channel* grpc_channel_create_with_builder(
}
channel->target = target;
+ channel->resource_user = resource_user;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT;
- size_t channel_tracer_max_memory = 0; // default to off
+ size_t channel_tracer_max_memory =
+ GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT;
bool internal_channel = false;
// this creates the default ChannelNode. Different types of channels may
// override this to ensure a correct ChannelNode is created.
@@ -142,7 +148,6 @@ grpc_channel* grpc_channel_create_with_builder(
0x1; /* always support no compression */
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) {
- GPR_ASSERT(channel_tracer_max_memory == 0);
const grpc_integer_options options = {
GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX};
channel_tracer_max_memory =
@@ -217,7 +222,8 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
- grpc_transport* optional_transport) {
+ grpc_transport* optional_transport,
+ grpc_resource_user* resource_user) {
grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
const grpc_core::UniquePtr<char> default_authority =
get_default_authority(input_args);
@@ -227,11 +233,17 @@ grpc_channel* grpc_channel_create(const char* target,
grpc_channel_args_destroy(args);
grpc_channel_stack_builder_set_target(builder, target);
grpc_channel_stack_builder_set_transport(builder, optional_transport);
+ grpc_channel_stack_builder_set_resource_user(builder, resource_user);
if (!grpc_channel_init_create_stack(builder, channel_stack_type)) {
grpc_channel_stack_builder_destroy(builder);
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
return nullptr;
}
- return grpc_channel_create_with_builder(builder, channel_stack_type);
+ grpc_channel* channel =
+ grpc_channel_create_with_builder(builder, channel_stack_type);
+ return channel;
}
size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) {
@@ -310,8 +322,8 @@ static grpc_call* grpc_channel_create_call_internal(
}
grpc_call_create_args args;
- memset(&args, 0, sizeof(args));
args.channel = channel;
+ args.server = nullptr;
args.parent = parent_call;
args.propagation_mask = propagation_mask;
args.cq = cq;
@@ -441,6 +453,10 @@ static void destroy_channel(void* arg, grpc_error* error) {
GRPC_MDELEM_UNREF(rc->authority);
gpr_free(rc);
}
+ if (channel->resource_user != nullptr) {
+ grpc_resource_user_free(channel->resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 4ac76b8a29..ab00b8e94f 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -29,7 +29,8 @@
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* args,
grpc_channel_stack_type channel_stack_type,
- grpc_transport* optional_transport);
+ grpc_transport* optional_transport,
+ grpc_resource_user* resource_user = nullptr);
grpc_channel* grpc_channel_create_with_builder(
grpc_channel_stack_builder* builder,
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index b81ae73b4d..661022ec5f 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -859,8 +859,8 @@ static void cq_end_op_for_callback(
gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
- cq_finish_shutdown_callback(cq);
gpr_mu_unlock(cq->mu);
+ cq_finish_shutdown_callback(cq);
} else {
gpr_mu_unlock(cq->mu);
}
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index 0ad82fed99..67cf5d89bf 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -123,6 +123,7 @@ void grpc_init(void) {
grpc_core::Fork::GlobalInit();
grpc_fork_handlers_auto_register();
gpr_time_init();
+ gpr_arena_init();
grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();
@@ -160,6 +161,7 @@ void grpc_shutdown(void) {
if (--g_initializations == 0) {
{
grpc_core::ExecCtx exec_ctx(0);
+ grpc_iomgr_shutdown_background_closure();
{
grpc_timer_manager_set_threading(
false); // shutdown timer_manager thread
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index 35ab2c3bce..67b38e6f0c 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -28,6 +28,8 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <utility>
+
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/debug/stats.h"
@@ -47,6 +49,10 @@
grpc_core::TraceFlag grpc_server_channel_trace(false, "server_channel");
+static void server_on_recv_initial_metadata(void* ptr, grpc_error* error);
+static void server_recv_trailing_metadata_ready(void* user_data,
+ grpc_error* error);
+
namespace {
struct listener {
void* arg;
@@ -105,7 +111,7 @@ struct channel_data {
uint32_t registered_method_max_probes;
grpc_closure finish_destroy_channel_closure;
grpc_closure channel_connectivity_changed;
- intptr_t socket_uuid;
+ grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> socket_node;
};
typedef struct shutdown_tag {
@@ -128,46 +134,73 @@ typedef enum {
typedef struct request_matcher request_matcher;
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call(grpc_call_from_top_element(elem)),
+ call_combiner(args.call_combiner) {
+ GRPC_CLOSURE_INIT(&server_on_recv_initial_metadata,
+ ::server_on_recv_initial_metadata, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ server_recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ }
+ ~call_data() {
+ GPR_ASSERT(state != PENDING);
+ GRPC_ERROR_UNREF(recv_initial_metadata_error);
+ if (host_set) {
+ grpc_slice_unref_internal(host);
+ }
+ if (path_set) {
+ grpc_slice_unref_internal(path);
+ }
+ grpc_metadata_array_destroy(&initial_metadata);
+ grpc_byte_buffer_destroy(payload);
+ }
+
grpc_call* call;
- gpr_atm state;
+ gpr_atm state = NOT_STARTED;
- bool path_set;
- bool host_set;
+ bool path_set = false;
+ bool host_set = false;
grpc_slice path;
grpc_slice host;
- grpc_millis deadline;
+ grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
- grpc_completion_queue* cq_new;
+ grpc_completion_queue* cq_new = nullptr;
- grpc_metadata_batch* recv_initial_metadata;
- uint32_t recv_initial_metadata_flags;
- grpc_metadata_array initial_metadata;
+ grpc_metadata_batch* recv_initial_metadata = nullptr;
+ uint32_t recv_initial_metadata_flags = 0;
+ grpc_metadata_array initial_metadata =
+ grpc_metadata_array(); // Zero-initialize the C struct.
- request_matcher* matcher;
- grpc_byte_buffer* payload;
+ request_matcher* matcher = nullptr;
+ grpc_byte_buffer* payload = nullptr;
grpc_closure got_initial_metadata;
grpc_closure server_on_recv_initial_metadata;
grpc_closure kill_zombie_closure;
grpc_closure* on_done_recv_initial_metadata;
grpc_closure recv_trailing_metadata_ready;
- grpc_error* recv_initial_metadata_error;
+ grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
grpc_closure* original_recv_trailing_metadata_ready;
- grpc_error* recv_trailing_metadata_error;
- bool seen_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE;
+ bool seen_recv_trailing_metadata_ready = false;
grpc_closure publish;
- call_data* pending_next;
+ call_data* pending_next = nullptr;
grpc_call_combiner* call_combiner;
};
struct request_matcher {
+ request_matcher(grpc_server* server);
+ ~request_matcher();
+
grpc_server* server;
- call_data* pending_head;
- call_data* pending_tail;
- gpr_locked_mpscq* requests_per_cq;
+ std::atomic<call_data*> pending_head{nullptr};
+ call_data* pending_tail = nullptr;
+ gpr_locked_mpscq* requests_per_cq = nullptr;
};
struct registered_method {
@@ -189,6 +222,8 @@ typedef struct {
struct grpc_server {
grpc_channel_args* channel_args;
+ grpc_resource_user* default_resource_user;
+
grpc_completion_queue** cqs;
grpc_pollset** pollsets;
size_t cq_count;
@@ -314,22 +349,30 @@ static void channel_broadcaster_shutdown(channel_broadcaster* cb,
* request_matcher
*/
-static void request_matcher_init(request_matcher* rm, grpc_server* server) {
- memset(rm, 0, sizeof(*rm));
- rm->server = server;
- rm->requests_per_cq = static_cast<gpr_locked_mpscq*>(
- gpr_malloc(sizeof(*rm->requests_per_cq) * server->cq_count));
+namespace {
+request_matcher::request_matcher(grpc_server* server) : server(server) {
+ requests_per_cq = static_cast<gpr_locked_mpscq*>(
+ gpr_malloc(sizeof(*requests_per_cq) * server->cq_count));
for (size_t i = 0; i < server->cq_count; i++) {
- gpr_locked_mpscq_init(&rm->requests_per_cq[i]);
+ gpr_locked_mpscq_init(&requests_per_cq[i]);
}
}
-static void request_matcher_destroy(request_matcher* rm) {
- for (size_t i = 0; i < rm->server->cq_count; i++) {
- GPR_ASSERT(gpr_locked_mpscq_pop(&rm->requests_per_cq[i]) == nullptr);
- gpr_locked_mpscq_destroy(&rm->requests_per_cq[i]);
+request_matcher::~request_matcher() {
+ for (size_t i = 0; i < server->cq_count; i++) {
+ GPR_ASSERT(gpr_locked_mpscq_pop(&requests_per_cq[i]) == nullptr);
+ gpr_locked_mpscq_destroy(&requests_per_cq[i]);
}
- gpr_free(rm->requests_per_cq);
+ gpr_free(requests_per_cq);
+}
+} // namespace
+
+static void request_matcher_init(request_matcher* rm, grpc_server* server) {
+ new (rm) request_matcher(server);
+}
+
+static void request_matcher_destroy(request_matcher* rm) {
+ rm->~request_matcher();
}
static void kill_zombie(void* elem, grpc_error* error) {
@@ -338,9 +381,10 @@ static void kill_zombie(void* elem, grpc_error* error) {
}
static void request_matcher_zombify_all_pending_calls(request_matcher* rm) {
- while (rm->pending_head) {
- call_data* calld = rm->pending_head;
- rm->pending_head = calld->pending_next;
+ call_data* calld;
+ while ((calld = rm->pending_head.load(std::memory_order_relaxed)) !=
+ nullptr) {
+ rm->pending_head.store(calld->pending_next, std::memory_order_relaxed);
gpr_atm_no_barrier_store(&calld->state, ZOMBIED);
GRPC_CLOSURE_INIT(
&calld->kill_zombie_closure, kill_zombie,
@@ -538,8 +582,9 @@ static void publish_new_rpc(void* arg, grpc_error* error) {
}
gpr_atm_no_barrier_store(&calld->state, PENDING);
- if (rm->pending_head == nullptr) {
- rm->pending_tail = rm->pending_head = calld;
+ if (rm->pending_head.load(std::memory_order_relaxed) == nullptr) {
+ rm->pending_head.store(calld, std::memory_order_relaxed);
+ rm->pending_tail = calld;
} else {
rm->pending_tail->pending_next = calld;
rm->pending_tail = calld;
@@ -822,11 +867,16 @@ static void accept_stream(void* cd, grpc_transport* transport,
channel_data* chand = static_cast<channel_data*>(cd);
/* create a call */
grpc_call_create_args args;
- memset(&args, 0, sizeof(args));
args.channel = chand->channel;
+ args.server = chand->server;
+ args.parent = nullptr;
+ args.propagation_mask = 0;
+ args.cq = nullptr;
+ args.pollset_set_alternative = nullptr;
args.server_transport_data = transport_server_data;
+ args.add_initial_metadata = nullptr;
+ args.add_initial_metadata_count = 0;
args.send_deadline = GRPC_MILLIS_INF_FUTURE;
- args.server = chand->server;
grpc_call* call;
grpc_error* error = grpc_call_create(&args, &call);
grpc_call_element* elem =
@@ -838,8 +888,9 @@ static void accept_stream(void* cd, grpc_transport* transport,
}
call_data* calld = static_cast<call_data*>(elem->call_data);
grpc_op op;
- memset(&op, 0, sizeof(op));
op.op = GRPC_OP_RECV_INITIAL_METADATA;
+ op.flags = 0;
+ op.reserved = nullptr;
op.data.recv_initial_metadata.recv_initial_metadata =
&calld->initial_metadata;
GRPC_CLOSURE_INIT(&calld->got_initial_metadata, got_initial_metadata, elem,
@@ -867,40 +918,18 @@ static void channel_connectivity_changed(void* cd, grpc_error* error) {
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- memset(calld, 0, sizeof(call_data));
- calld->deadline = GRPC_MILLIS_INF_FUTURE;
- calld->call = grpc_call_from_top_element(elem);
- calld->call_combiner = args->call_combiner;
-
- GRPC_CLOSURE_INIT(&calld->server_on_recv_initial_metadata,
- server_on_recv_initial_metadata, elem,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
- server_recv_trailing_metadata_ready, elem,
- grpc_schedule_on_exec_ctx);
server_ref(chand->server);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
- channel_data* chand = static_cast<channel_data*>(elem->channel_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
-
- GPR_ASSERT(calld->state != PENDING);
- GRPC_ERROR_UNREF(calld->recv_initial_metadata_error);
- if (calld->host_set) {
- grpc_slice_unref_internal(calld->host);
- }
- if (calld->path_set) {
- grpc_slice_unref_internal(calld->path);
- }
- grpc_metadata_array_destroy(&calld->initial_metadata);
- grpc_byte_buffer_destroy(calld->payload);
-
+ calld->~call_data();
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
server_unref(chand->server);
}
@@ -923,6 +952,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
static void destroy_channel_elem(grpc_channel_element* elem) {
size_t i;
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ chand->socket_node.reset();
if (chand->registered_methods) {
for (i = 0; i < chand->registered_method_slots; i++) {
grpc_slice_unref_internal(chand->registered_methods[i].method);
@@ -1024,6 +1054,15 @@ grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) {
grpc_slice_from_static_string("Server created"));
}
+ if (args != nullptr) {
+ grpc_resource_quota* resource_quota =
+ grpc_resource_quota_from_channel_args(args, false /* create */);
+ if (resource_quota != nullptr) {
+ server->default_resource_user =
+ grpc_resource_user_create(resource_quota, "default");
+ }
+ }
+
return server;
}
@@ -1119,10 +1158,11 @@ void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets,
*pollsets = server->pollsets;
}
-void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
- grpc_pollset* accepting_pollset,
- const grpc_channel_args* args,
- intptr_t socket_uuid) {
+void grpc_server_setup_transport(
+ grpc_server* s, grpc_transport* transport, grpc_pollset* accepting_pollset,
+ const grpc_channel_args* args,
+ grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> socket_node,
+ grpc_resource_user* resource_user) {
size_t num_registered_methods;
size_t alloc;
registered_method* rm;
@@ -1135,14 +1175,15 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
uint32_t max_probes = 0;
grpc_transport_op* op = nullptr;
- channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport);
+ channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport,
+ resource_user);
chand = static_cast<channel_data*>(
grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0)
->channel_data);
chand->server = s;
server_ref(s);
chand->channel = channel;
- chand->socket_uuid = socket_uuid;
+ chand->socket_node = std::move(socket_node);
size_t cq_idx;
for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) {
@@ -1218,14 +1259,13 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
}
void grpc_server_populate_server_sockets(
- grpc_server* s, grpc_core::channelz::ChildRefsList* server_sockets,
+ grpc_server* s, grpc_core::channelz::ChildSocketsList* server_sockets,
intptr_t start_idx) {
gpr_mu_lock(&s->mu_global);
channel_data* c = nullptr;
for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
- intptr_t socket_uuid = c->socket_uuid;
- if (socket_uuid >= start_idx) {
- server_sockets->push_back(socket_uuid);
+ if (c->socket_node != nullptr && c->socket_node->uuid() >= start_idx) {
+ server_sockets->push_back(c->socket_node.get());
}
}
gpr_mu_unlock(&s->mu_global);
@@ -1330,6 +1370,13 @@ void grpc_server_shutdown_and_notify(grpc_server* server,
channel_broadcaster_shutdown(&broadcaster, true /* send_goaway */,
GRPC_ERROR_NONE);
+
+ if (server->default_resource_user != nullptr) {
+ grpc_resource_quota_unref(
+ grpc_resource_user_quota(server->default_resource_user));
+ grpc_resource_user_shutdown(server->default_resource_user);
+ grpc_resource_user_unref(server->default_resource_user);
+ }
}
void grpc_server_cancel_all_calls(grpc_server* server) {
@@ -1401,30 +1448,39 @@ static grpc_call_error queue_call_request(grpc_server* server, size_t cq_idx,
rm = &rc->data.registered.method->matcher;
break;
}
- if (gpr_locked_mpscq_push(&rm->requests_per_cq[cq_idx], &rc->request_link)) {
- /* this was the first queued request: we need to lock and start
- matching calls */
- gpr_mu_lock(&server->mu_call);
- while ((calld = rm->pending_head) != nullptr) {
- rc = reinterpret_cast<requested_call*>(
- gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]));
- if (rc == nullptr) break;
- rm->pending_head = calld->pending_next;
- gpr_mu_unlock(&server->mu_call);
- if (!gpr_atm_full_cas(&calld->state, PENDING, ACTIVATED)) {
- // Zombied Call
- GRPC_CLOSURE_INIT(
- &calld->kill_zombie_closure, kill_zombie,
- grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0),
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_SCHED(&calld->kill_zombie_closure, GRPC_ERROR_NONE);
- } else {
- publish_call(server, calld, cq_idx, rc);
- }
- gpr_mu_lock(&server->mu_call);
- }
+
+ // Fast path: if there is no pending request to be processed, immediately
+ // return.
+ if (!gpr_locked_mpscq_push(&rm->requests_per_cq[cq_idx], &rc->request_link) ||
+ // Note: We are reading the pending_head without holding the server's call
+ // mutex. Even if we read a non-null value here due to reordering,
+ // we will check it below again after grabbing the lock.
+ rm->pending_head.load(std::memory_order_relaxed) == nullptr) {
+ return GRPC_CALL_OK;
+ }
+ // Slow path: This was the first queued request and there are pendings:
+ // We need to lock and start matching calls.
+ gpr_mu_lock(&server->mu_call);
+ while ((calld = rm->pending_head.load(std::memory_order_relaxed)) !=
+ nullptr) {
+ rc = reinterpret_cast<requested_call*>(
+ gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]));
+ if (rc == nullptr) break;
+ rm->pending_head.store(calld->pending_next, std::memory_order_relaxed);
gpr_mu_unlock(&server->mu_call);
+ if (!gpr_atm_full_cas(&calld->state, PENDING, ACTIVATED)) {
+ // Zombied Call
+ GRPC_CLOSURE_INIT(
+ &calld->kill_zombie_closure, kill_zombie,
+ grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0),
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_SCHED(&calld->kill_zombie_closure, GRPC_ERROR_NONE);
+ } else {
+ publish_call(server, calld, cq_idx, rc);
+ }
+ gpr_mu_lock(&server->mu_call);
}
+ gpr_mu_unlock(&server->mu_call);
return GRPC_CALL_OK;
}
@@ -1546,6 +1602,10 @@ const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server) {
return server->channel_args;
}
+grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server) {
+ return server->default_resource_user;
+}
+
int grpc_server_has_open_connections(grpc_server* server) {
int r;
gpr_mu_lock(&server->mu_global);
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
index 33c205417e..393bb24214 100644
--- a/src/core/lib/surface/server.h
+++ b/src/core/lib/surface/server.h
@@ -44,14 +44,15 @@ void grpc_server_add_listener(grpc_server* server, void* listener,
/* Setup a transport - creates a channel stack, binds the transport to the
server */
-void grpc_server_setup_transport(grpc_server* server, grpc_transport* transport,
- grpc_pollset* accepting_pollset,
- const grpc_channel_args* args,
- intptr_t socket_uuid);
+void grpc_server_setup_transport(
+ grpc_server* server, grpc_transport* transport,
+ grpc_pollset* accepting_pollset, const grpc_channel_args* args,
+ grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> socket_node,
+ grpc_resource_user* resource_user = nullptr);
/* fills in the uuids of all sockets used for connections on this server */
void grpc_server_populate_server_sockets(
- grpc_server* server, grpc_core::channelz::ChildRefsList* server_sockets,
+ grpc_server* server, grpc_core::channelz::ChildSocketsList* server_sockets,
intptr_t start_idx);
/* fills in the uuids of all listen sockets on this server */
@@ -63,6 +64,8 @@ grpc_core::channelz::ServerNode* grpc_server_get_channelz_node(
const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server);
+grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server);
+
int grpc_server_has_open_connections(grpc_server* server);
/* Do not call this before grpc_server_start. Returns the pollsets and the
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index 66890ce65a..4829cc80a5 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -25,4 +25,4 @@
const char* grpc_version_string(void) { return "7.0.0-dev"; }
-const char* grpc_g_stands_for(void) { return "gizmo"; }
+const char* grpc_g_stands_for(void) { return "goose"; }
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 0bcbb32d1f..f6e8bbf205 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -31,9 +31,11 @@
#include "src/core/lib/transport/static_metadata.h"
typedef struct grpc_linked_mdelem {
+ grpc_linked_mdelem() {}
+
grpc_mdelem md;
- struct grpc_linked_mdelem* next;
- struct grpc_linked_mdelem* prev;
+ struct grpc_linked_mdelem* next = nullptr;
+ struct grpc_linked_mdelem* prev = nullptr;
void* reserved;
} grpc_linked_mdelem;
diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc
index 4ebe73f82a..3dfaaaad5c 100644
--- a/src/core/lib/transport/static_metadata.cc
+++ b/src/core/lib/transport/static_metadata.cc
@@ -65,51 +65,56 @@ static uint8_t g_bytes[] = {
97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111,
97, 100, 47, 103, 114, 112, 99, 46, 104, 101, 97, 108, 116, 104, 46,
118, 49, 46, 72, 101, 97, 108, 116, 104, 47, 87, 97, 116, 99, 104,
- 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116, 114, 101,
- 97, 109, 47, 103, 122, 105, 112, 71, 69, 84, 80, 79, 83, 84, 47,
- 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 104, 116, 116, 112,
- 104, 116, 116, 112, 115, 50, 48, 48, 50, 48, 52, 50, 48, 54, 51,
- 48, 52, 52, 48, 48, 52, 48, 52, 53, 48, 48, 97, 99, 99, 101,
- 112, 116, 45, 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44,
- 32, 100, 101, 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45,
- 108, 97, 110, 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45,
- 114, 97, 110, 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99,
- 101, 115, 115, 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108,
- 111, 119, 45, 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108,
- 111, 119, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110,
- 99, 97, 99, 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111,
- 110, 116, 101, 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105,
- 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117,
- 97, 103, 101, 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103,
- 116, 104, 99, 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116,
- 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103,
- 101, 99, 111, 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103,
- 101, 120, 112, 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114,
- 111, 109, 105, 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111,
- 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45,
- 110, 111, 110, 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97,
- 110, 103, 101, 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101,
- 100, 45, 115, 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100,
- 105, 102, 105, 101, 100, 108, 105, 110, 107, 108, 111, 99, 97, 116, 105,
- 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114, 100, 115, 112,
- 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97,
- 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 111, 114, 105,
- 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114, 101, 102, 101,
- 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121,
- 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116,
- 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99, 116, 45, 116,
- 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99, 117, 114, 105,
- 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101, 110, 99, 111,
- 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119, 119, 119, 45,
- 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 48, 105, 100,
- 101, 110, 116, 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97,
- 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99,
- 103, 114, 112, 99, 80, 85, 84, 108, 98, 45, 99, 111, 115, 116, 45,
- 98, 105, 110, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102,
- 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 103, 122,
- 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112, 105,
- 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101,
- 44, 103, 122, 105, 112};
+ 47, 101, 110, 118, 111, 121, 46, 115, 101, 114, 118, 105, 99, 101, 46,
+ 100, 105, 115, 99, 111, 118, 101, 114, 121, 46, 118, 50, 46, 65, 103,
+ 103, 114, 101, 103, 97, 116, 101, 100, 68, 105, 115, 99, 111, 118, 101,
+ 114, 121, 83, 101, 114, 118, 105, 99, 101, 47, 83, 116, 114, 101, 97,
+ 109, 65, 103, 103, 114, 101, 103, 97, 116, 101, 100, 82, 101, 115, 111,
+ 117, 114, 99, 101, 115, 100, 101, 102, 108, 97, 116, 101, 103, 122, 105,
+ 112, 115, 116, 114, 101, 97, 109, 47, 103, 122, 105, 112, 71, 69, 84,
+ 80, 79, 83, 84, 47, 47, 105, 110, 100, 101, 120, 46, 104, 116, 109,
+ 108, 104, 116, 116, 112, 104, 116, 116, 112, 115, 50, 48, 48, 50, 48,
+ 52, 50, 48, 54, 51, 48, 52, 52, 48, 48, 52, 48, 52, 53, 48,
+ 48, 97, 99, 99, 101, 112, 116, 45, 99, 104, 97, 114, 115, 101, 116,
+ 103, 122, 105, 112, 44, 32, 100, 101, 102, 108, 97, 116, 101, 97, 99,
+ 99, 101, 112, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101, 97, 99,
+ 99, 101, 112, 116, 45, 114, 97, 110, 103, 101, 115, 97, 99, 99, 101,
+ 112, 116, 97, 99, 99, 101, 115, 115, 45, 99, 111, 110, 116, 114, 111,
+ 108, 45, 97, 108, 108, 111, 119, 45, 111, 114, 105, 103, 105, 110, 97,
+ 103, 101, 97, 108, 108, 111, 119, 97, 117, 116, 104, 111, 114, 105, 122,
+ 97, 116, 105, 111, 110, 99, 97, 99, 104, 101, 45, 99, 111, 110, 116,
+ 114, 111, 108, 99, 111, 110, 116, 101, 110, 116, 45, 100, 105, 115, 112,
+ 111, 115, 105, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45,
+ 108, 97, 110, 103, 117, 97, 103, 101, 99, 111, 110, 116, 101, 110, 116,
+ 45, 108, 101, 110, 103, 116, 104, 99, 111, 110, 116, 101, 110, 116, 45,
+ 108, 111, 99, 97, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116,
+ 45, 114, 97, 110, 103, 101, 99, 111, 111, 107, 105, 101, 100, 97, 116,
+ 101, 101, 116, 97, 103, 101, 120, 112, 101, 99, 116, 101, 120, 112, 105,
+ 114, 101, 115, 102, 114, 111, 109, 105, 102, 45, 109, 97, 116, 99, 104,
+ 105, 102, 45, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115, 105, 110,
+ 99, 101, 105, 102, 45, 110, 111, 110, 101, 45, 109, 97, 116, 99, 104,
+ 105, 102, 45, 114, 97, 110, 103, 101, 105, 102, 45, 117, 110, 109, 111,
+ 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 108, 97, 115,
+ 116, 45, 109, 111, 100, 105, 102, 105, 101, 100, 108, 105, 110, 107, 108,
+ 111, 99, 97, 116, 105, 111, 110, 109, 97, 120, 45, 102, 111, 114, 119,
+ 97, 114, 100, 115, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 101,
+ 110, 116, 105, 99, 97, 116, 101, 112, 114, 111, 120, 121, 45, 97, 117,
+ 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 114, 97, 110, 103,
+ 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114, 101, 115, 104,
+ 114, 101, 116, 114, 121, 45, 97, 102, 116, 101, 114, 115, 101, 114, 118,
+ 101, 114, 115, 101, 116, 45, 99, 111, 111, 107, 105, 101, 115, 116, 114,
+ 105, 99, 116, 45, 116, 114, 97, 110, 115, 112, 111, 114, 116, 45, 115,
+ 101, 99, 117, 114, 105, 116, 121, 116, 114, 97, 110, 115, 102, 101, 114,
+ 45, 101, 110, 99, 111, 100, 105, 110, 103, 118, 97, 114, 121, 118, 105,
+ 97, 119, 119, 119, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97,
+ 116, 101, 48, 105, 100, 101, 110, 116, 105, 116, 121, 116, 114, 97, 105,
+ 108, 101, 114, 115, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110,
+ 47, 103, 114, 112, 99, 103, 114, 112, 99, 80, 85, 84, 108, 98, 45,
+ 99, 111, 115, 116, 45, 98, 105, 110, 105, 100, 101, 110, 116, 105, 116,
+ 121, 44, 100, 101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116, 105,
+ 116, 121, 44, 103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101, 44,
+ 103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101,
+ 102, 108, 97, 116, 101, 44, 103, 122, 105, 112};
static void static_ref(void* unused) {}
static void static_unref(void* unused) {}
@@ -227,6 +232,7 @@ grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
};
const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@@ -266,76 +272,77 @@ const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 28}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}},
- {&grpc_static_metadata_refcounts[38], {{g_bytes + 521, 11}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 532, 3}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 535, 4}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 539, 1}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 540, 11}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 551, 4}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 555, 5}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 560, 3}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 563, 3}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 566, 3}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 569, 3}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 572, 3}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 575, 3}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 578, 3}}},
- {&grpc_static_metadata_refcounts[52], {{g_bytes + 581, 14}}},
- {&grpc_static_metadata_refcounts[53], {{g_bytes + 595, 13}}},
- {&grpc_static_metadata_refcounts[54], {{g_bytes + 608, 15}}},
- {&grpc_static_metadata_refcounts[55], {{g_bytes + 623, 13}}},
- {&grpc_static_metadata_refcounts[56], {{g_bytes + 636, 6}}},
- {&grpc_static_metadata_refcounts[57], {{g_bytes + 642, 27}}},
- {&grpc_static_metadata_refcounts[58], {{g_bytes + 669, 3}}},
- {&grpc_static_metadata_refcounts[59], {{g_bytes + 672, 5}}},
- {&grpc_static_metadata_refcounts[60], {{g_bytes + 677, 13}}},
- {&grpc_static_metadata_refcounts[61], {{g_bytes + 690, 13}}},
- {&grpc_static_metadata_refcounts[62], {{g_bytes + 703, 19}}},
- {&grpc_static_metadata_refcounts[63], {{g_bytes + 722, 16}}},
- {&grpc_static_metadata_refcounts[64], {{g_bytes + 738, 14}}},
- {&grpc_static_metadata_refcounts[65], {{g_bytes + 752, 16}}},
- {&grpc_static_metadata_refcounts[66], {{g_bytes + 768, 13}}},
- {&grpc_static_metadata_refcounts[67], {{g_bytes + 781, 6}}},
- {&grpc_static_metadata_refcounts[68], {{g_bytes + 787, 4}}},
- {&grpc_static_metadata_refcounts[69], {{g_bytes + 791, 4}}},
- {&grpc_static_metadata_refcounts[70], {{g_bytes + 795, 6}}},
- {&grpc_static_metadata_refcounts[71], {{g_bytes + 801, 7}}},
- {&grpc_static_metadata_refcounts[72], {{g_bytes + 808, 4}}},
- {&grpc_static_metadata_refcounts[73], {{g_bytes + 812, 8}}},
- {&grpc_static_metadata_refcounts[74], {{g_bytes + 820, 17}}},
- {&grpc_static_metadata_refcounts[75], {{g_bytes + 837, 13}}},
- {&grpc_static_metadata_refcounts[76], {{g_bytes + 850, 8}}},
- {&grpc_static_metadata_refcounts[77], {{g_bytes + 858, 19}}},
- {&grpc_static_metadata_refcounts[78], {{g_bytes + 877, 13}}},
- {&grpc_static_metadata_refcounts[79], {{g_bytes + 890, 4}}},
- {&grpc_static_metadata_refcounts[80], {{g_bytes + 894, 8}}},
- {&grpc_static_metadata_refcounts[81], {{g_bytes + 902, 12}}},
- {&grpc_static_metadata_refcounts[82], {{g_bytes + 914, 18}}},
- {&grpc_static_metadata_refcounts[83], {{g_bytes + 932, 19}}},
- {&grpc_static_metadata_refcounts[84], {{g_bytes + 951, 5}}},
- {&grpc_static_metadata_refcounts[85], {{g_bytes + 956, 7}}},
- {&grpc_static_metadata_refcounts[86], {{g_bytes + 963, 7}}},
- {&grpc_static_metadata_refcounts[87], {{g_bytes + 970, 11}}},
- {&grpc_static_metadata_refcounts[88], {{g_bytes + 981, 6}}},
- {&grpc_static_metadata_refcounts[89], {{g_bytes + 987, 10}}},
- {&grpc_static_metadata_refcounts[90], {{g_bytes + 997, 25}}},
- {&grpc_static_metadata_refcounts[91], {{g_bytes + 1022, 17}}},
- {&grpc_static_metadata_refcounts[92], {{g_bytes + 1039, 4}}},
- {&grpc_static_metadata_refcounts[93], {{g_bytes + 1043, 3}}},
- {&grpc_static_metadata_refcounts[94], {{g_bytes + 1046, 16}}},
- {&grpc_static_metadata_refcounts[95], {{g_bytes + 1062, 1}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}},
- {&grpc_static_metadata_refcounts[97], {{g_bytes + 1071, 8}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1079, 16}}},
- {&grpc_static_metadata_refcounts[99], {{g_bytes + 1095, 4}}},
- {&grpc_static_metadata_refcounts[100], {{g_bytes + 1099, 3}}},
- {&grpc_static_metadata_refcounts[101], {{g_bytes + 1102, 11}}},
- {&grpc_static_metadata_refcounts[102], {{g_bytes + 1113, 16}}},
- {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}},
- {&grpc_static_metadata_refcounts[104], {{g_bytes + 1142, 12}}},
- {&grpc_static_metadata_refcounts[105], {{g_bytes + 1154, 21}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 80}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 601, 11}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 612, 3}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 615, 4}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 619, 1}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 620, 11}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 631, 4}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 635, 5}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 640, 3}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 643, 3}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 646, 3}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 649, 3}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 652, 3}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 655, 3}}},
+ {&grpc_static_metadata_refcounts[52], {{g_bytes + 658, 3}}},
+ {&grpc_static_metadata_refcounts[53], {{g_bytes + 661, 14}}},
+ {&grpc_static_metadata_refcounts[54], {{g_bytes + 675, 13}}},
+ {&grpc_static_metadata_refcounts[55], {{g_bytes + 688, 15}}},
+ {&grpc_static_metadata_refcounts[56], {{g_bytes + 703, 13}}},
+ {&grpc_static_metadata_refcounts[57], {{g_bytes + 716, 6}}},
+ {&grpc_static_metadata_refcounts[58], {{g_bytes + 722, 27}}},
+ {&grpc_static_metadata_refcounts[59], {{g_bytes + 749, 3}}},
+ {&grpc_static_metadata_refcounts[60], {{g_bytes + 752, 5}}},
+ {&grpc_static_metadata_refcounts[61], {{g_bytes + 757, 13}}},
+ {&grpc_static_metadata_refcounts[62], {{g_bytes + 770, 13}}},
+ {&grpc_static_metadata_refcounts[63], {{g_bytes + 783, 19}}},
+ {&grpc_static_metadata_refcounts[64], {{g_bytes + 802, 16}}},
+ {&grpc_static_metadata_refcounts[65], {{g_bytes + 818, 14}}},
+ {&grpc_static_metadata_refcounts[66], {{g_bytes + 832, 16}}},
+ {&grpc_static_metadata_refcounts[67], {{g_bytes + 848, 13}}},
+ {&grpc_static_metadata_refcounts[68], {{g_bytes + 861, 6}}},
+ {&grpc_static_metadata_refcounts[69], {{g_bytes + 867, 4}}},
+ {&grpc_static_metadata_refcounts[70], {{g_bytes + 871, 4}}},
+ {&grpc_static_metadata_refcounts[71], {{g_bytes + 875, 6}}},
+ {&grpc_static_metadata_refcounts[72], {{g_bytes + 881, 7}}},
+ {&grpc_static_metadata_refcounts[73], {{g_bytes + 888, 4}}},
+ {&grpc_static_metadata_refcounts[74], {{g_bytes + 892, 8}}},
+ {&grpc_static_metadata_refcounts[75], {{g_bytes + 900, 17}}},
+ {&grpc_static_metadata_refcounts[76], {{g_bytes + 917, 13}}},
+ {&grpc_static_metadata_refcounts[77], {{g_bytes + 930, 8}}},
+ {&grpc_static_metadata_refcounts[78], {{g_bytes + 938, 19}}},
+ {&grpc_static_metadata_refcounts[79], {{g_bytes + 957, 13}}},
+ {&grpc_static_metadata_refcounts[80], {{g_bytes + 970, 4}}},
+ {&grpc_static_metadata_refcounts[81], {{g_bytes + 974, 8}}},
+ {&grpc_static_metadata_refcounts[82], {{g_bytes + 982, 12}}},
+ {&grpc_static_metadata_refcounts[83], {{g_bytes + 994, 18}}},
+ {&grpc_static_metadata_refcounts[84], {{g_bytes + 1012, 19}}},
+ {&grpc_static_metadata_refcounts[85], {{g_bytes + 1031, 5}}},
+ {&grpc_static_metadata_refcounts[86], {{g_bytes + 1036, 7}}},
+ {&grpc_static_metadata_refcounts[87], {{g_bytes + 1043, 7}}},
+ {&grpc_static_metadata_refcounts[88], {{g_bytes + 1050, 11}}},
+ {&grpc_static_metadata_refcounts[89], {{g_bytes + 1061, 6}}},
+ {&grpc_static_metadata_refcounts[90], {{g_bytes + 1067, 10}}},
+ {&grpc_static_metadata_refcounts[91], {{g_bytes + 1077, 25}}},
+ {&grpc_static_metadata_refcounts[92], {{g_bytes + 1102, 17}}},
+ {&grpc_static_metadata_refcounts[93], {{g_bytes + 1119, 4}}},
+ {&grpc_static_metadata_refcounts[94], {{g_bytes + 1123, 3}}},
+ {&grpc_static_metadata_refcounts[95], {{g_bytes + 1126, 16}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1142, 1}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}},
+ {&grpc_static_metadata_refcounts[98], {{g_bytes + 1151, 8}}},
+ {&grpc_static_metadata_refcounts[99], {{g_bytes + 1159, 16}}},
+ {&grpc_static_metadata_refcounts[100], {{g_bytes + 1175, 4}}},
+ {&grpc_static_metadata_refcounts[101], {{g_bytes + 1179, 3}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1182, 11}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1193, 16}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}},
+ {&grpc_static_metadata_refcounts[105], {{g_bytes + 1222, 12}}},
+ {&grpc_static_metadata_refcounts[106], {{g_bytes + 1234, 21}}},
};
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@@ -345,17 +352,17 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4};
static const int8_t elems_r[] = {
- 16, 11, -8, 0, 3, -42, -81, -43, 0, 6, -8, 0, 0, 0, -7,
- -3, -10, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, -63, 0, -47, -68, -69, -70, 0, 33,
- 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 20,
- 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
- 4, 4, 4, 3, 10, 9, 0, 0, 0, 0, 0, 0, -3, 0};
+ 15, 10, -8, 0, 2, -42, -81, -43, 0, 6, -8, 0, 0, 0, 2,
+ -3, -10, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -64, 0, -67, -68, -69, -70, 0,
+ 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
+ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
+ 5, 4, 5, 4, 4, 8, 8, 0, 0, 0, 0, 0, 0, -5, 0};
static uint32_t elems_phash(uint32_t i) {
- i -= 41;
- uint32_t x = i % 104;
- uint32_t y = i / 104;
+ i -= 42;
+ uint32_t x = i % 105;
+ uint32_t y = i / 105;
uint32_t h = x;
if (y < GPR_ARRAY_SIZE(elems_r)) {
uint32_t delta = (uint32_t)elems_r[y];
@@ -365,29 +372,29 @@ static uint32_t elems_phash(uint32_t i) {
}
static const uint16_t elem_keys[] = {
- 257, 258, 259, 260, 261, 262, 263, 1096, 1097, 1513, 1725, 145,
- 146, 467, 468, 1619, 41, 42, 1733, 990, 991, 767, 768, 1627,
- 627, 837, 2043, 2149, 2255, 5541, 5859, 5965, 6071, 6177, 1749, 6283,
- 6389, 6495, 6601, 6707, 6813, 6919, 7025, 7131, 7237, 7343, 7449, 7555,
- 7661, 5753, 7767, 7873, 7979, 8085, 8191, 8297, 8403, 8509, 8615, 8721,
- 8827, 8933, 9039, 9145, 9251, 9357, 9463, 1156, 9569, 523, 9675, 9781,
- 206, 1162, 1163, 1164, 1165, 1792, 1582, 1050, 9887, 9993, 1686, 10735,
- 1799, 0, 0, 0, 0, 0, 347, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0};
+ 260, 261, 262, 263, 264, 265, 266, 1107, 1108, 1741, 147, 148,
+ 472, 473, 1634, 42, 43, 1527, 1750, 1000, 1001, 774, 775, 1643,
+ 633, 845, 2062, 2169, 2276, 5700, 5914, 6021, 6128, 6235, 1766, 6342,
+ 6449, 6556, 6663, 6770, 6877, 6984, 7091, 7198, 7305, 7412, 7519, 7626,
+ 7733, 7840, 7947, 8054, 8161, 8268, 8375, 8482, 8589, 8696, 8803, 8910,
+ 9017, 9124, 9231, 9338, 9445, 9552, 9659, 1167, 528, 9766, 9873, 208,
+ 9980, 1173, 1174, 1175, 1176, 1809, 10087, 1060, 10194, 10943, 1702, 0,
+ 1816, 0, 0, 1597, 0, 0, 350, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0};
static const uint8_t elem_idxs[] = {
- 7, 8, 9, 10, 11, 12, 13, 77, 79, 30, 71, 1, 2, 5, 6, 25,
- 3, 4, 84, 66, 65, 62, 63, 73, 67, 61, 57, 37, 74, 14, 17, 18,
- 19, 20, 15, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34, 35,
- 36, 16, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 76, 55, 69, 56, 58, 70, 78, 80, 81, 82, 83, 68, 64,
- 59, 60, 72, 75, 85, 255, 255, 255, 255, 255, 0};
+ 7, 8, 9, 10, 11, 12, 13, 77, 79, 71, 1, 2, 5, 6, 25, 3,
+ 4, 30, 84, 66, 65, 62, 63, 73, 67, 61, 57, 37, 74, 14, 16, 17,
+ 18, 19, 15, 20, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34,
+ 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 76, 69, 55, 56, 70, 58, 78, 80, 81, 82, 83, 59, 64,
+ 60, 75, 72, 255, 85, 255, 255, 68, 255, 255, 0};
grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
if (a == -1 || b == -1) return GRPC_MDNULL;
- uint32_t k = (uint32_t)(a * 106 + b);
+ uint32_t k = (uint32_t)(a * 107 + b);
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
@@ -400,175 +407,175 @@ grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 532, 3}}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 612, 3}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 535, 4}}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 615, 4}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 539, 1}}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 619, 1}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 540, 11}}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 620, 11}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 551, 4}}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 631, 4}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 555, 5}}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 635, 5}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 560, 3}}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 640, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 563, 3}}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 643, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 566, 3}}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 646, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 569, 3}}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 649, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 572, 3}}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 652, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 575, 3}}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 655, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 578, 3}}}},
- {{&grpc_static_metadata_refcounts[52], {{g_bytes + 581, 14}}},
+ {&grpc_static_metadata_refcounts[52], {{g_bytes + 658, 3}}}},
+ {{&grpc_static_metadata_refcounts[53], {{g_bytes + 661, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[53], {{g_bytes + 595, 13}}}},
- {{&grpc_static_metadata_refcounts[54], {{g_bytes + 608, 15}}},
+ {&grpc_static_metadata_refcounts[54], {{g_bytes + 675, 13}}}},
+ {{&grpc_static_metadata_refcounts[55], {{g_bytes + 688, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[55], {{g_bytes + 623, 13}}},
+ {{&grpc_static_metadata_refcounts[56], {{g_bytes + 703, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[56], {{g_bytes + 636, 6}}},
+ {{&grpc_static_metadata_refcounts[57], {{g_bytes + 716, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[57], {{g_bytes + 642, 27}}},
+ {{&grpc_static_metadata_refcounts[58], {{g_bytes + 722, 27}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[58], {{g_bytes + 669, 3}}},
+ {{&grpc_static_metadata_refcounts[59], {{g_bytes + 749, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[59], {{g_bytes + 672, 5}}},
+ {{&grpc_static_metadata_refcounts[60], {{g_bytes + 752, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[60], {{g_bytes + 677, 13}}},
+ {{&grpc_static_metadata_refcounts[61], {{g_bytes + 757, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[61], {{g_bytes + 690, 13}}},
+ {{&grpc_static_metadata_refcounts[62], {{g_bytes + 770, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[62], {{g_bytes + 703, 19}}},
+ {{&grpc_static_metadata_refcounts[63], {{g_bytes + 783, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[63], {{g_bytes + 722, 16}}},
+ {{&grpc_static_metadata_refcounts[64], {{g_bytes + 802, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[64], {{g_bytes + 738, 14}}},
+ {{&grpc_static_metadata_refcounts[65], {{g_bytes + 818, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[65], {{g_bytes + 752, 16}}},
+ {{&grpc_static_metadata_refcounts[66], {{g_bytes + 832, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[66], {{g_bytes + 768, 13}}},
+ {{&grpc_static_metadata_refcounts[67], {{g_bytes + 848, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[67], {{g_bytes + 781, 6}}},
+ {{&grpc_static_metadata_refcounts[68], {{g_bytes + 861, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[68], {{g_bytes + 787, 4}}},
+ {{&grpc_static_metadata_refcounts[69], {{g_bytes + 867, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[69], {{g_bytes + 791, 4}}},
+ {{&grpc_static_metadata_refcounts[70], {{g_bytes + 871, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[70], {{g_bytes + 795, 6}}},
+ {{&grpc_static_metadata_refcounts[71], {{g_bytes + 875, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[71], {{g_bytes + 801, 7}}},
+ {{&grpc_static_metadata_refcounts[72], {{g_bytes + 881, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[72], {{g_bytes + 808, 4}}},
+ {{&grpc_static_metadata_refcounts[73], {{g_bytes + 888, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[73], {{g_bytes + 812, 8}}},
+ {{&grpc_static_metadata_refcounts[74], {{g_bytes + 892, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[74], {{g_bytes + 820, 17}}},
+ {{&grpc_static_metadata_refcounts[75], {{g_bytes + 900, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[75], {{g_bytes + 837, 13}}},
+ {{&grpc_static_metadata_refcounts[76], {{g_bytes + 917, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[76], {{g_bytes + 850, 8}}},
+ {{&grpc_static_metadata_refcounts[77], {{g_bytes + 930, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[77], {{g_bytes + 858, 19}}},
+ {{&grpc_static_metadata_refcounts[78], {{g_bytes + 938, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[78], {{g_bytes + 877, 13}}},
+ {{&grpc_static_metadata_refcounts[79], {{g_bytes + 957, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[79], {{g_bytes + 890, 4}}},
+ {{&grpc_static_metadata_refcounts[80], {{g_bytes + 970, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[80], {{g_bytes + 894, 8}}},
+ {{&grpc_static_metadata_refcounts[81], {{g_bytes + 974, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[81], {{g_bytes + 902, 12}}},
+ {{&grpc_static_metadata_refcounts[82], {{g_bytes + 982, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[82], {{g_bytes + 914, 18}}},
+ {{&grpc_static_metadata_refcounts[83], {{g_bytes + 994, 18}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[83], {{g_bytes + 932, 19}}},
+ {{&grpc_static_metadata_refcounts[84], {{g_bytes + 1012, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[84], {{g_bytes + 951, 5}}},
+ {{&grpc_static_metadata_refcounts[85], {{g_bytes + 1031, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[85], {{g_bytes + 956, 7}}},
+ {{&grpc_static_metadata_refcounts[86], {{g_bytes + 1036, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[86], {{g_bytes + 963, 7}}},
+ {{&grpc_static_metadata_refcounts[87], {{g_bytes + 1043, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[87], {{g_bytes + 970, 11}}},
+ {{&grpc_static_metadata_refcounts[88], {{g_bytes + 1050, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[88], {{g_bytes + 981, 6}}},
+ {{&grpc_static_metadata_refcounts[89], {{g_bytes + 1061, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[89], {{g_bytes + 987, 10}}},
+ {{&grpc_static_metadata_refcounts[90], {{g_bytes + 1067, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[90], {{g_bytes + 997, 25}}},
+ {{&grpc_static_metadata_refcounts[91], {{g_bytes + 1077, 25}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[91], {{g_bytes + 1022, 17}}},
+ {{&grpc_static_metadata_refcounts[92], {{g_bytes + 1102, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[92], {{g_bytes + 1039, 4}}},
+ {{&grpc_static_metadata_refcounts[93], {{g_bytes + 1119, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[93], {{g_bytes + 1043, 3}}},
+ {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1123, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1046, 16}}},
+ {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1126, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[95], {{g_bytes + 1062, 1}}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1142, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}}},
{{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
- {&grpc_static_metadata_refcounts[97], {{g_bytes + 1071, 8}}}},
+ {&grpc_static_metadata_refcounts[98], {{g_bytes + 1151, 8}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1079, 16}}}},
+ {&grpc_static_metadata_refcounts[99], {{g_bytes + 1159, 16}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[99], {{g_bytes + 1095, 4}}}},
+ {&grpc_static_metadata_refcounts[100], {{g_bytes + 1175, 4}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[100], {{g_bytes + 1099, 3}}}},
+ {&grpc_static_metadata_refcounts[101], {{g_bytes + 1179, 3}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[101], {{g_bytes + 1102, 11}}},
+ {{&grpc_static_metadata_refcounts[102], {{g_bytes + 1182, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[102], {{g_bytes + 1113, 16}}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1193, 16}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[104], {{g_bytes + 1142, 12}}}},
+ {&grpc_static_metadata_refcounts[105], {{g_bytes + 1222, 12}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[105], {{g_bytes + 1154, 21}}}},
+ {&grpc_static_metadata_refcounts[106], {{g_bytes + 1234, 21}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}}},
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 2bb9f72838..4f9670232c 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -31,7 +31,7 @@
#include "src/core/lib/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 106
+#define GRPC_STATIC_MDSTR_COUNT 107
extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* ":path" */
#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@@ -110,147 +110,151 @@ extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* "/grpc.health.v1.Health/Watch" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_HEALTH_DOT_V1_DOT_HEALTH_SLASH_WATCH \
(grpc_static_slice_table[35])
+/* "/envoy.service.discovery.v2.AggregatedDiscoveryService/StreamAggregatedResources"
+ */
+#define GRPC_MDSTR_SLASH_ENVOY_DOT_SERVICE_DOT_DISCOVERY_DOT_V2_DOT_AGGREGATEDDISCOVERYSERVICE_SLASH_STREAMAGGREGATEDRESOURCES \
+ (grpc_static_slice_table[36])
/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[36])
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[37])
/* "gzip" */
-#define GRPC_MDSTR_GZIP (grpc_static_slice_table[37])
+#define GRPC_MDSTR_GZIP (grpc_static_slice_table[38])
/* "stream/gzip" */
-#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[38])
+#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[39])
/* "GET" */
-#define GRPC_MDSTR_GET (grpc_static_slice_table[39])
+#define GRPC_MDSTR_GET (grpc_static_slice_table[40])
/* "POST" */
-#define GRPC_MDSTR_POST (grpc_static_slice_table[40])
+#define GRPC_MDSTR_POST (grpc_static_slice_table[41])
/* "/" */
-#define GRPC_MDSTR_SLASH (grpc_static_slice_table[41])
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[42])
/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[42])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[43])
/* "http" */
-#define GRPC_MDSTR_HTTP (grpc_static_slice_table[43])
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[44])
/* "https" */
-#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[44])
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[45])
/* "200" */
-#define GRPC_MDSTR_200 (grpc_static_slice_table[45])
+#define GRPC_MDSTR_200 (grpc_static_slice_table[46])
/* "204" */
-#define GRPC_MDSTR_204 (grpc_static_slice_table[46])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[47])
/* "206" */
-#define GRPC_MDSTR_206 (grpc_static_slice_table[47])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[48])
/* "304" */
-#define GRPC_MDSTR_304 (grpc_static_slice_table[48])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[49])
/* "400" */
-#define GRPC_MDSTR_400 (grpc_static_slice_table[49])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[50])
/* "404" */
-#define GRPC_MDSTR_404 (grpc_static_slice_table[50])
+#define GRPC_MDSTR_404 (grpc_static_slice_table[51])
/* "500" */
-#define GRPC_MDSTR_500 (grpc_static_slice_table[51])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[52])
/* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[52])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[53])
/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[53])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[54])
/* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[54])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[55])
/* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[55])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[56])
/* "accept" */
-#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[56])
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[57])
/* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[57])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[58])
/* "age" */
-#define GRPC_MDSTR_AGE (grpc_static_slice_table[58])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[59])
/* "allow" */
-#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[59])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[60])
/* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[60])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[61])
/* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[61])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[62])
/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[62])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[63])
/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[63])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[64])
/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[64])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[65])
/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[65])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[66])
/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[66])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[67])
/* "cookie" */
-#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[67])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[68])
/* "date" */
-#define GRPC_MDSTR_DATE (grpc_static_slice_table[68])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[69])
/* "etag" */
-#define GRPC_MDSTR_ETAG (grpc_static_slice_table[69])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[70])
/* "expect" */
-#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[70])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[71])
/* "expires" */
-#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[71])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[72])
/* "from" */
-#define GRPC_MDSTR_FROM (grpc_static_slice_table[72])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[73])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[73])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[74])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[74])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[75])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[75])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[76])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[76])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[77])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[77])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[78])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[78])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[79])
/* "link" */
-#define GRPC_MDSTR_LINK (grpc_static_slice_table[79])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[80])
/* "location" */
-#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[80])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[81])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[81])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[82])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[82])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[83])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[83])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[84])
/* "range" */
-#define GRPC_MDSTR_RANGE (grpc_static_slice_table[84])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[85])
/* "referer" */
-#define GRPC_MDSTR_REFERER (grpc_static_slice_table[85])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[86])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[86])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[87])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[87])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[88])
/* "server" */
-#define GRPC_MDSTR_SERVER (grpc_static_slice_table[88])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[89])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[89])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[90])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[90])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[91])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[91])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[92])
/* "vary" */
-#define GRPC_MDSTR_VARY (grpc_static_slice_table[92])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[93])
/* "via" */
-#define GRPC_MDSTR_VIA (grpc_static_slice_table[93])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[94])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[94])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[95])
/* "0" */
-#define GRPC_MDSTR_0 (grpc_static_slice_table[95])
+#define GRPC_MDSTR_0 (grpc_static_slice_table[96])
/* "identity" */
-#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[96])
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[97])
/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[97])
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[98])
/* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[98])
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[99])
/* "grpc" */
-#define GRPC_MDSTR_GRPC (grpc_static_slice_table[99])
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[100])
/* "PUT" */
-#define GRPC_MDSTR_PUT (grpc_static_slice_table[100])
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[101])
/* "lb-cost-bin" */
-#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[101])
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[102])
/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[102])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[103])
/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[103])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[104])
/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[104])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[105])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (grpc_static_slice_table[105])
+ (grpc_static_slice_table[106])
extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
extern grpc_slice_refcount
diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc
index cbdb77c844..b32f9c6ec1 100644
--- a/src/core/lib/transport/transport.cc
+++ b/src/core/lib/transport/transport.cc
@@ -27,6 +27,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/slice/slice_internal.h"
@@ -149,7 +150,7 @@ void grpc_transport_move_stats(grpc_transport_stream_stats* from,
}
size_t grpc_transport_stream_size(grpc_transport* transport) {
- return transport->vtable->sizeof_stream;
+ return GPR_ROUND_UP_TO_ALIGNMENT_SIZE(transport->vtable->sizeof_stream);
}
void grpc_transport_destroy(grpc_transport* transport) {
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 9e784635c6..5ce568834e 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -81,16 +81,16 @@ void grpc_stream_unref(grpc_stream_refcount* refcount);
grpc_slice grpc_slice_from_stream_owned_buffer(grpc_stream_refcount* refcount,
void* buffer, size_t length);
-typedef struct {
- uint64_t framing_bytes;
- uint64_t data_bytes;
- uint64_t header_bytes;
-} grpc_transport_one_way_stats;
+struct grpc_transport_one_way_stats {
+ uint64_t framing_bytes = 0;
+ uint64_t data_bytes = 0;
+ uint64_t header_bytes = 0;
+};
-typedef struct grpc_transport_stream_stats {
+struct grpc_transport_stream_stats {
grpc_transport_one_way_stats incoming;
grpc_transport_one_way_stats outgoing;
-} grpc_transport_stream_stats;
+};
void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats* from,
grpc_transport_one_way_stats* to);
@@ -121,7 +121,17 @@ typedef struct grpc_transport_stream_op_batch_payload
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
-typedef struct grpc_transport_stream_op_batch {
+struct grpc_transport_stream_op_batch {
+ grpc_transport_stream_op_batch()
+ : send_initial_metadata(false),
+ send_trailing_metadata(false),
+ send_message(false),
+ recv_initial_metadata(false),
+ recv_message(false),
+ recv_trailing_metadata(false),
+ cancel_stream(false),
+ is_traced(false) {}
+
/** Should be scheduled when all of the non-recv operations in the batch
are complete.
@@ -131,10 +141,10 @@ typedef struct grpc_transport_stream_op_batch {
scheduled as soon as the non-recv ops are complete, regardless of
whether or not the recv ops are complete. If a batch contains
only recv ops, on_complete can be null. */
- grpc_closure* on_complete;
+ grpc_closure* on_complete = nullptr;
/** Values for the stream op (fields set are determined by flags above) */
- grpc_transport_stream_op_batch_payload* payload;
+ grpc_transport_stream_op_batch_payload* payload = nullptr;
/** Send initial metadata to the peer, from the provided metadata batch. */
bool send_initial_metadata : 1;
@@ -158,29 +168,41 @@ typedef struct grpc_transport_stream_op_batch {
/** Cancel this stream with the provided error */
bool cancel_stream : 1;
+ /** Is this stream traced */
+ bool is_traced : 1;
+
/***************************************************************************
* remaining fields are initialized and used at the discretion of the
* current handler of the op */
grpc_handler_private_op_data handler_private;
-} grpc_transport_stream_op_batch;
+};
struct grpc_transport_stream_op_batch_payload {
+ explicit grpc_transport_stream_op_batch_payload(
+ grpc_call_context_element* context)
+ : context(context) {}
+ ~grpc_transport_stream_op_batch_payload() {
+ // We don't really own `send_message`, so release ownership and let the
+ // owner clean the data.
+ send_message.send_message.release();
+ }
+
struct {
- grpc_metadata_batch* send_initial_metadata;
+ grpc_metadata_batch* send_initial_metadata = nullptr;
/** Iff send_initial_metadata != NULL, flags associated with
send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */
- uint32_t send_initial_metadata_flags;
+ uint32_t send_initial_metadata_flags = 0;
// If non-NULL, will be set by the transport to the peer string (a char*).
// The transport retains ownership of the string.
// Note: This pointer may be used by the transport after the
// send_initial_metadata op is completed. It must remain valid
// until the call is destroyed.
- gpr_atm* peer_string;
+ gpr_atm* peer_string = nullptr;
} send_initial_metadata;
struct {
- grpc_metadata_batch* send_trailing_metadata;
+ grpc_metadata_batch* send_trailing_metadata = nullptr;
} send_trailing_metadata;
struct {
@@ -192,39 +214,39 @@ struct grpc_transport_stream_op_batch_payload {
} send_message;
struct {
- grpc_metadata_batch* recv_initial_metadata;
+ grpc_metadata_batch* recv_initial_metadata = nullptr;
// Flags are used only on the server side. If non-null, will be set to
// a bitfield of the GRPC_INITIAL_METADATA_xxx macros (e.g., to
// indicate if the call is idempotent).
- uint32_t* recv_flags;
+ uint32_t* recv_flags = nullptr;
/** Should be enqueued when initial metadata is ready to be processed. */
- grpc_closure* recv_initial_metadata_ready;
+ grpc_closure* recv_initial_metadata_ready = nullptr;
// If not NULL, will be set to true if trailing metadata is
// immediately available. This may be a signal that we received a
// Trailers-Only response.
- bool* trailing_metadata_available;
+ bool* trailing_metadata_available = nullptr;
// If non-NULL, will be set by the transport to the peer string (a char*).
// The transport retains ownership of the string.
// Note: This pointer may be used by the transport after the
// recv_initial_metadata op is completed. It must remain valid
// until the call is destroyed.
- gpr_atm* peer_string;
+ gpr_atm* peer_string = nullptr;
} recv_initial_metadata;
struct {
// Will be set by the transport to point to the byte stream
// containing a received message.
// Will be NULL if trailing metadata is received instead of a message.
- grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
+ grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr;
/** Should be enqueued when one message is ready to be processed. */
- grpc_closure* recv_message_ready;
+ grpc_closure* recv_message_ready = nullptr;
} recv_message;
struct {
- grpc_metadata_batch* recv_trailing_metadata;
- grpc_transport_stream_stats* collect_stats;
+ grpc_metadata_batch* recv_trailing_metadata = nullptr;
+ grpc_transport_stream_stats* collect_stats = nullptr;
/** Should be enqueued when initial metadata is ready to be processed. */
- grpc_closure* recv_trailing_metadata_ready;
+ grpc_closure* recv_trailing_metadata_ready = nullptr;
} recv_trailing_metadata;
/** Forcefully close this stream.
@@ -240,7 +262,7 @@ struct grpc_transport_stream_op_batch_payload {
struct {
// Error contract: the transport that gets this op must cause cancel_error
// to be unref'ed after processing it
- grpc_error* cancel_error;
+ grpc_error* cancel_error = GRPC_ERROR_NONE;
} cancel_stream;
/* Indexes correspond to grpc_context_index enum values */
diff --git a/src/core/ext/filters/client_channel/uri_parser.cc b/src/core/lib/uri/uri_parser.cc
index 0572034a9c..f212c7d2c0 100644
--- a/src/core/ext/filters/client_channel/uri_parser.cc
+++ b/src/core/lib/uri/uri_parser.cc
@@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
-#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/uri/uri_parser.h"
#include <string.h>
diff --git a/src/core/ext/filters/client_channel/uri_parser.h b/src/core/lib/uri/uri_parser.h
index d749f23308..b6771bbde3 100644
--- a/src/core/ext/filters/client_channel/uri_parser.h
+++ b/src/core/lib/uri/uri_parser.h
@@ -16,8 +16,8 @@
*
*/
-#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
-#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
+#ifndef GRPC_CORE_LIB_URI_URI_PARSER_H
+#define GRPC_CORE_LIB_URI_URI_PARSER_H
#include <grpc/support/port_platform.h>
@@ -47,4 +47,4 @@ const char* grpc_uri_get_query_arg(const grpc_uri* uri, const char* key);
/** destroy a uri */
void grpc_uri_destroy(grpc_uri* uri);
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H */
+#endif /* GRPC_CORE_LIB_URI_URI_PARSER_H */
diff --git a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
index c0c17b0a4b..92085d31d7 100644
--- a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
@@ -28,8 +28,6 @@ void grpc_deadline_filter_init(void);
void grpc_deadline_filter_shutdown(void);
void grpc_client_channel_init(void);
void grpc_client_channel_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
void grpc_register_built_in_plugins(void) {
grpc_register_plugin(grpc_http_filters_init,
@@ -40,6 +38,4 @@ void grpc_register_built_in_plugins(void) {
grpc_deadline_filter_shutdown);
grpc_register_plugin(grpc_client_channel_init,
grpc_client_channel_shutdown);
- grpc_register_plugin(grpc_tsi_alts_init,
- grpc_tsi_alts_shutdown);
}
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index 94c2493d5e..cde40ef65c 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -28,8 +28,6 @@ void grpc_deadline_filter_init(void);
void grpc_deadline_filter_shutdown(void);
void grpc_client_channel_init(void);
void grpc_client_channel_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
void grpc_inproc_plugin_init(void);
void grpc_inproc_plugin_shutdown(void);
void grpc_resolver_fake_init(void);
@@ -66,8 +64,6 @@ void grpc_register_built_in_plugins(void) {
grpc_deadline_filter_shutdown);
grpc_register_plugin(grpc_client_channel_init,
grpc_client_channel_shutdown);
- grpc_register_plugin(grpc_tsi_alts_init,
- grpc_tsi_alts_shutdown);
grpc_register_plugin(grpc_inproc_plugin_init,
grpc_inproc_plugin_shutdown);
grpc_register_plugin(grpc_resolver_fake_init,
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
index 17e8026096..43d0979f4b 100644
--- a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
@@ -25,30 +25,172 @@
#include <grpc/support/log.h>
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
+#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
+
+#define TSI_ALTS_INITIAL_BUFFER_SIZE 256
const int kHandshakerClientOpNum = 4;
+struct alts_handshaker_client {
+ const alts_handshaker_client_vtable* vtable;
+};
+
typedef struct alts_grpc_handshaker_client {
alts_handshaker_client base;
+ alts_tsi_handshaker* handshaker;
grpc_call* call;
+ /* A pointer to a function handling the interaction with handshaker service.
+ * That is, it points to grpc_call_start_batch_and_execute when the handshaker
+ * client is used in a non-testing use case and points to a custom function
+ * that validates the data to be sent to handshaker service in a testing use
+ * case. */
alts_grpc_caller grpc_caller;
+ /* A callback function provided by gRPC to handle the response returned from
+ * handshaker service. It also serves to bring the control safely back to
+ * application when dedicated CQ and thread are used. */
+ grpc_iomgr_cb_func grpc_cb;
+ /* A gRPC closure to be scheduled when the response from handshaker service
+ * is received. It will be initialized with grpc_cb. */
+ grpc_closure on_handshaker_service_resp_recv;
+ /* Buffers containing information to be sent (or received) to (or from) the
+ * handshaker service. */
+ grpc_byte_buffer* send_buffer;
+ grpc_byte_buffer* recv_buffer;
+ grpc_status_code status;
+ /* Initial metadata to be received from handshaker service. */
+ grpc_metadata_array recv_initial_metadata;
+ /* A callback function provided by an application to be invoked when response
+ * is received from handshaker service. */
+ tsi_handshaker_on_next_done_cb cb;
+ void* user_data;
+ /* ALTS credential options passed in from the caller. */
+ grpc_alts_credentials_options* options;
+ /* target name information to be passed to handshaker service for server
+ * authorization check. */
+ grpc_slice target_name;
+ /* boolean flag indicating if the handshaker client is used at client
+ * (is_client = true) or server (is_client = false) side. */
+ bool is_client;
+ /* a temporary store for data received from handshaker service used to extract
+ * unused data. */
+ grpc_slice recv_bytes;
+ /* a buffer containing data to be sent to the grpc client or server's peer. */
+ unsigned char* buffer;
+ size_t buffer_size;
} alts_grpc_handshaker_client;
-static grpc_call_error grpc_start_batch(grpc_call* call, const grpc_op* ops,
- size_t nops, void* tag) {
- return grpc_call_start_batch(call, ops, nops, tag, nullptr);
+static void handshaker_client_send_buffer_destroy(
+ alts_grpc_handshaker_client* client) {
+ GPR_ASSERT(client != nullptr);
+ grpc_byte_buffer_destroy(client->send_buffer);
+ client->send_buffer = nullptr;
+}
+
+static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) {
+ GPR_ASSERT(resp != nullptr);
+ if (resp->has_result) {
+ return true;
+ }
+ return false;
+}
+
+void alts_handshaker_client_handle_response(alts_handshaker_client* c,
+ bool is_ok) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ grpc_byte_buffer* recv_buffer = client->recv_buffer;
+ grpc_status_code status = client->status;
+ tsi_handshaker_on_next_done_cb cb = client->cb;
+ void* user_data = client->user_data;
+ alts_tsi_handshaker* handshaker = client->handshaker;
+
+ /* Invalid input check. */
+ if (cb == nullptr) {
+ gpr_log(GPR_ERROR,
+ "cb is nullptr in alts_tsi_handshaker_handle_response()");
+ return;
+ }
+ if (handshaker == nullptr) {
+ gpr_log(GPR_ERROR,
+ "handshaker is nullptr in alts_tsi_handshaker_handle_response()");
+ cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
+ return;
+ }
+ /* TSI handshake has been shutdown. */
+ if (alts_tsi_handshaker_has_shutdown(handshaker)) {
+ gpr_log(GPR_ERROR, "TSI handshake shutdown");
+ cb(TSI_HANDSHAKE_SHUTDOWN, user_data, nullptr, 0, nullptr);
+ return;
+ }
+ /* Failed grpc call check. */
+ if (!is_ok || status != GRPC_STATUS_OK) {
+ gpr_log(GPR_ERROR, "grpc call made to handshaker service failed");
+ cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
+ return;
+ }
+ if (recv_buffer == nullptr) {
+ gpr_log(GPR_ERROR,
+ "recv_buffer is nullptr in alts_tsi_handshaker_handle_response()");
+ cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
+ return;
+ }
+ grpc_gcp_handshaker_resp* resp =
+ alts_tsi_utils_deserialize_response(recv_buffer);
+ grpc_byte_buffer_destroy(client->recv_buffer);
+ client->recv_buffer = nullptr;
+ /* Invalid handshaker response check. */
+ if (resp == nullptr) {
+ gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed");
+ cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr);
+ return;
+ }
+ grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg);
+ unsigned char* bytes_to_send = nullptr;
+ size_t bytes_to_send_size = 0;
+ if (slice != nullptr) {
+ bytes_to_send_size = GRPC_SLICE_LENGTH(*slice);
+ while (bytes_to_send_size > client->buffer_size) {
+ client->buffer_size *= 2;
+ client->buffer = static_cast<unsigned char*>(
+ gpr_realloc(client->buffer, client->buffer_size));
+ }
+ memcpy(client->buffer, GRPC_SLICE_START_PTR(*slice), bytes_to_send_size);
+ bytes_to_send = client->buffer;
+ }
+ tsi_handshaker_result* result = nullptr;
+ if (is_handshake_finished_properly(resp)) {
+ alts_tsi_handshaker_result_create(resp, client->is_client, &result);
+ alts_tsi_handshaker_result_set_unused_bytes(result, &client->recv_bytes,
+ resp->bytes_consumed);
+ }
+ grpc_status_code code = static_cast<grpc_status_code>(resp->status.code);
+ if (code != GRPC_STATUS_OK) {
+ grpc_slice* details = static_cast<grpc_slice*>(resp->status.details.arg);
+ if (details != nullptr) {
+ char* error_details = grpc_slice_to_c_string(*details);
+ gpr_log(GPR_ERROR, "Error from handshaker service:%s", error_details);
+ gpr_free(error_details);
+ }
+ }
+ grpc_gcp_handshaker_resp_destroy(resp);
+ cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send,
+ bytes_to_send_size, result);
}
/**
- * Populate grpc operation data with the fields of ALTS TSI event and make a
- * grpc call.
+ * Populate grpc operation data with the fields of ALTS handshaker client and
+ * make a grpc call.
*/
-static tsi_result make_grpc_call(alts_handshaker_client* client,
- alts_tsi_event* event, bool is_start) {
- GPR_ASSERT(client != nullptr && event != nullptr);
- alts_grpc_handshaker_client* grpc_client =
- reinterpret_cast<alts_grpc_handshaker_client*>(client);
+static tsi_result make_grpc_call(alts_handshaker_client* c, bool is_start) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
grpc_op ops[kHandshakerClientOpNum];
memset(ops, 0, sizeof(ops));
grpc_op* op = ops;
@@ -59,22 +201,22 @@ static tsi_result make_grpc_call(alts_handshaker_client* client,
GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata =
- &event->initial_metadata;
+ &client->recv_initial_metadata;
op++;
GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
}
op->op = GRPC_OP_SEND_MESSAGE;
- op->data.send_message.send_message = event->send_buffer;
+ op->data.send_message.send_message = client->send_buffer;
op++;
GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
op->op = GRPC_OP_RECV_MESSAGE;
- op->data.recv_message.recv_message = &event->recv_buffer;
+ op->data.recv_message.recv_message = &client->recv_buffer;
op++;
GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
- GPR_ASSERT(grpc_client->grpc_caller != nullptr);
- if (grpc_client->grpc_caller(grpc_client->call, ops,
- static_cast<size_t>(op - ops),
- (void*)event) != GRPC_CALL_OK) {
+ GPR_ASSERT(client->grpc_caller != nullptr);
+ if (client->grpc_caller(client->call, ops, static_cast<size_t>(op - ops),
+ &client->on_handshaker_service_resp_recv) !=
+ GRPC_CALL_OK) {
gpr_log(GPR_ERROR, "Start batch operation failed");
return TSI_INTERNAL_ERROR;
}
@@ -82,7 +224,11 @@ static tsi_result make_grpc_call(alts_handshaker_client* client,
}
/* Create and populate a client_start handshaker request, then serialize it. */
-static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
+static grpc_byte_buffer* get_serialized_start_client(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
bool ok = true;
grpc_gcp_handshaker_req* req =
grpc_gcp_handshaker_req_create(CLIENT_START_REQ);
@@ -91,14 +237,14 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
ok &= grpc_gcp_handshaker_req_add_application_protocol(
req, ALTS_APPLICATION_PROTOCOL);
ok &= grpc_gcp_handshaker_req_add_record_protocol(req, ALTS_RECORD_PROTOCOL);
- grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
+ grpc_gcp_rpc_protocol_versions* versions = &client->options->rpc_versions;
ok &= grpc_gcp_handshaker_req_set_rpc_versions(
req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
versions->min_rpc_version.major, versions->min_rpc_version.minor);
- char* target_name = grpc_slice_to_c_string(event->target_name);
+ char* target_name = grpc_slice_to_c_string(client->target_name);
ok &= grpc_gcp_handshaker_req_set_target_name(req, target_name);
target_service_account* ptr =
- (reinterpret_cast<grpc_alts_credentials_client_options*>(event->options))
+ (reinterpret_cast<grpc_alts_credentials_client_options*>(client->options))
->target_account_list_head;
while (ptr != nullptr) {
grpc_gcp_handshaker_req_add_target_identity_service_account(req, ptr->data);
@@ -116,19 +262,21 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
return buffer;
}
-static tsi_result handshaker_client_start_client(alts_handshaker_client* client,
- alts_tsi_event* event) {
- if (client == nullptr || event == nullptr) {
- gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_client()");
+static tsi_result handshaker_client_start_client(alts_handshaker_client* c) {
+ if (c == nullptr) {
+ gpr_log(GPR_ERROR, "client is nullptr in handshaker_client_start_client()");
return TSI_INVALID_ARGUMENT;
}
- grpc_byte_buffer* buffer = get_serialized_start_client(event);
+ grpc_byte_buffer* buffer = get_serialized_start_client(c);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
if (buffer == nullptr) {
gpr_log(GPR_ERROR, "get_serialized_start_client() failed");
return TSI_INTERNAL_ERROR;
}
- event->send_buffer = buffer;
- tsi_result result = make_grpc_call(client, event, true /* is_start */);
+ handshaker_client_send_buffer_destroy(client);
+ client->send_buffer = buffer;
+ tsi_result result = make_grpc_call(&client->base, true /* is_start */);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "make_grpc_call() failed");
}
@@ -137,8 +285,11 @@ static tsi_result handshaker_client_start_client(alts_handshaker_client* client,
/* Create and populate a start_server handshaker request, then serialize it. */
static grpc_byte_buffer* get_serialized_start_server(
- alts_tsi_event* event, grpc_slice* bytes_received) {
+ alts_handshaker_client* c, grpc_slice* bytes_received) {
+ GPR_ASSERT(c != nullptr);
GPR_ASSERT(bytes_received != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
grpc_gcp_handshaker_req* req =
grpc_gcp_handshaker_req_create(SERVER_START_REQ);
bool ok = grpc_gcp_handshaker_req_add_application_protocol(
@@ -148,7 +299,7 @@ static grpc_byte_buffer* get_serialized_start_server(
ok &= grpc_gcp_handshaker_req_set_in_bytes(
req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received),
GRPC_SLICE_LENGTH(*bytes_received));
- grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
+ grpc_gcp_rpc_protocol_versions* versions = &client->options->rpc_versions;
ok &= grpc_gcp_handshaker_req_set_rpc_versions(
req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
versions->min_rpc_version.major, versions->min_rpc_version.minor);
@@ -163,20 +314,22 @@ static grpc_byte_buffer* get_serialized_start_server(
return buffer;
}
-static tsi_result handshaker_client_start_server(alts_handshaker_client* client,
- alts_tsi_event* event,
+static tsi_result handshaker_client_start_server(alts_handshaker_client* c,
grpc_slice* bytes_received) {
- if (client == nullptr || event == nullptr || bytes_received == nullptr) {
+ if (c == nullptr || bytes_received == nullptr) {
gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_server()");
return TSI_INVALID_ARGUMENT;
}
- grpc_byte_buffer* buffer = get_serialized_start_server(event, bytes_received);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ grpc_byte_buffer* buffer = get_serialized_start_server(c, bytes_received);
if (buffer == nullptr) {
gpr_log(GPR_ERROR, "get_serialized_start_server() failed");
return TSI_INTERNAL_ERROR;
}
- event->send_buffer = buffer;
- tsi_result result = make_grpc_call(client, event, true /* is_start */);
+ handshaker_client_send_buffer_destroy(client);
+ client->send_buffer = buffer;
+ tsi_result result = make_grpc_call(&client->base, true /* is_start */);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "make_grpc_call() failed");
}
@@ -201,40 +354,48 @@ static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) {
return buffer;
}
-static tsi_result handshaker_client_next(alts_handshaker_client* client,
- alts_tsi_event* event,
+static tsi_result handshaker_client_next(alts_handshaker_client* c,
grpc_slice* bytes_received) {
- if (client == nullptr || event == nullptr || bytes_received == nullptr) {
+ if (c == nullptr || bytes_received == nullptr) {
gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_next()");
return TSI_INVALID_ARGUMENT;
}
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ grpc_slice_unref_internal(client->recv_bytes);
+ client->recv_bytes = grpc_slice_ref(*bytes_received);
grpc_byte_buffer* buffer = get_serialized_next(bytes_received);
if (buffer == nullptr) {
gpr_log(GPR_ERROR, "get_serialized_next() failed");
return TSI_INTERNAL_ERROR;
}
- event->send_buffer = buffer;
- tsi_result result = make_grpc_call(client, event, false /* is_start */);
+ handshaker_client_send_buffer_destroy(client);
+ client->send_buffer = buffer;
+ tsi_result result = make_grpc_call(&client->base, false /* is_start */);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "make_grpc_call() failed");
}
return result;
}
-static void handshaker_client_shutdown(alts_handshaker_client* client) {
- GPR_ASSERT(client != nullptr);
- alts_grpc_handshaker_client* grpc_client =
- reinterpret_cast<alts_grpc_handshaker_client*>(client);
- GPR_ASSERT(grpc_call_cancel(grpc_client->call, nullptr) == GRPC_CALL_OK);
+static void handshaker_client_shutdown(alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ if (client->call != nullptr) {
+ grpc_call_cancel_internal(client->call);
+ }
}
-static void handshaker_client_destruct(alts_handshaker_client* client) {
- if (client == nullptr) {
+static void handshaker_client_destruct(alts_handshaker_client* c) {
+ if (c == nullptr) {
return;
}
- alts_grpc_handshaker_client* grpc_client =
- reinterpret_cast<alts_grpc_handshaker_client*>(client);
- grpc_call_unref(grpc_client->call);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ if (client->call != nullptr) {
+ grpc_call_unref(client->call);
+ }
}
static const alts_handshaker_client_vtable vtable = {
@@ -243,22 +404,45 @@ static const alts_handshaker_client_vtable vtable = {
handshaker_client_destruct};
alts_handshaker_client* alts_grpc_handshaker_client_create(
- grpc_channel* channel, grpc_completion_queue* queue,
- const char* handshaker_service_url) {
- if (channel == nullptr || queue == nullptr ||
- handshaker_service_url == nullptr) {
+ alts_tsi_handshaker* handshaker, grpc_channel* channel,
+ const char* handshaker_service_url, grpc_pollset_set* interested_parties,
+ grpc_alts_credentials_options* options, grpc_slice target_name,
+ grpc_iomgr_cb_func grpc_cb, tsi_handshaker_on_next_done_cb cb,
+ void* user_data, alts_handshaker_client_vtable* vtable_for_testing,
+ bool is_client) {
+ if (channel == nullptr || handshaker_service_url == nullptr) {
gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()");
return nullptr;
}
alts_grpc_handshaker_client* client =
static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client)));
- client->grpc_caller = grpc_start_batch;
+ client->grpc_caller = grpc_call_start_batch_and_execute;
+ client->handshaker = handshaker;
+ client->cb = cb;
+ client->user_data = user_data;
+ client->send_buffer = nullptr;
+ client->recv_buffer = nullptr;
+ client->options = grpc_alts_credentials_options_copy(options);
+ client->target_name = grpc_slice_copy(target_name);
+ client->recv_bytes = grpc_empty_slice();
+ grpc_metadata_array_init(&client->recv_initial_metadata);
+ client->grpc_cb = grpc_cb;
+ client->is_client = is_client;
+ client->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE;
+ client->buffer = static_cast<unsigned char*>(gpr_zalloc(client->buffer_size));
grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url);
- client->call = grpc_channel_create_call(
- channel, nullptr, GRPC_PROPAGATE_DEFAULTS, queue,
- grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice,
- gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
- client->base.vtable = &vtable;
+ client->call =
+ strcmp(handshaker_service_url, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING) ==
+ 0
+ ? nullptr
+ : grpc_channel_create_pollset_set_call(
+ channel, nullptr, GRPC_PROPAGATE_DEFAULTS, interested_parties,
+ grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice,
+ GRPC_MILLIS_INF_FUTURE, nullptr);
+ client->base.vtable =
+ vtable_for_testing == nullptr ? &vtable : vtable_for_testing;
+ GRPC_CLOSURE_INIT(&client->on_handshaker_service_resp_recv, client->grpc_cb,
+ client, grpc_schedule_on_exec_ctx);
grpc_slice_unref_internal(slice);
return &client->base;
}
@@ -267,21 +451,114 @@ namespace grpc_core {
namespace internal {
void alts_handshaker_client_set_grpc_caller_for_testing(
- alts_handshaker_client* client, alts_grpc_caller caller) {
- GPR_ASSERT(client != nullptr && caller != nullptr);
- alts_grpc_handshaker_client* grpc_client =
- reinterpret_cast<alts_grpc_handshaker_client*>(client);
- grpc_client->grpc_caller = caller;
+ alts_handshaker_client* c, alts_grpc_caller caller) {
+ GPR_ASSERT(c != nullptr && caller != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ client->grpc_caller = caller;
+}
+
+grpc_byte_buffer* alts_handshaker_client_get_send_buffer_for_testing(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ return client->send_buffer;
+}
+
+grpc_byte_buffer** alts_handshaker_client_get_recv_buffer_addr_for_testing(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ return &client->recv_buffer;
+}
+
+grpc_metadata_array* alts_handshaker_client_get_initial_metadata_for_testing(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ return &client->recv_initial_metadata;
+}
+
+void alts_handshaker_client_set_recv_bytes_for_testing(
+ alts_handshaker_client* c, grpc_slice* recv_bytes) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ client->recv_bytes = grpc_slice_ref(*recv_bytes);
+}
+
+void alts_handshaker_client_set_fields_for_testing(
+ alts_handshaker_client* c, alts_tsi_handshaker* handshaker,
+ tsi_handshaker_on_next_done_cb cb, void* user_data,
+ grpc_byte_buffer* recv_buffer, grpc_status_code status) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ client->handshaker = handshaker;
+ client->cb = cb;
+ client->user_data = user_data;
+ client->recv_buffer = recv_buffer;
+ client->status = status;
+}
+
+void alts_handshaker_client_check_fields_for_testing(
+ alts_handshaker_client* c, tsi_handshaker_on_next_done_cb cb,
+ void* user_data, bool has_sent_start_message, grpc_slice* recv_bytes) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ GPR_ASSERT(client->cb == cb);
+ GPR_ASSERT(client->user_data == user_data);
+ if (recv_bytes != nullptr) {
+ GPR_ASSERT(grpc_slice_cmp(client->recv_bytes, *recv_bytes) == 0);
+ }
+ GPR_ASSERT(alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+ client->handshaker) == has_sent_start_message);
+}
+
+void alts_handshaker_client_set_vtable_for_testing(
+ alts_handshaker_client* c, alts_handshaker_client_vtable* vtable) {
+ GPR_ASSERT(c != nullptr);
+ GPR_ASSERT(vtable != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ client->base.vtable = vtable;
+}
+
+alts_tsi_handshaker* alts_handshaker_client_get_handshaker_for_testing(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ return client->handshaker;
+}
+
+void alts_handshaker_client_set_cb_for_testing(
+ alts_handshaker_client* c, tsi_handshaker_on_next_done_cb cb) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ client->cb = cb;
+}
+
+grpc_closure* alts_handshaker_client_get_closure_for_testing(
+ alts_handshaker_client* c) {
+ GPR_ASSERT(c != nullptr);
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ return &client->on_handshaker_service_resp_recv;
}
} // namespace internal
} // namespace grpc_core
-tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
- alts_tsi_event* event) {
+tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client) {
if (client != nullptr && client->vtable != nullptr &&
client->vtable->client_start != nullptr) {
- return client->vtable->client_start(client, event);
+ return client->vtable->client_start(client);
}
gpr_log(GPR_ERROR,
"client or client->vtable has not been initialized properly");
@@ -289,11 +566,10 @@ tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
}
tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
- alts_tsi_event* event,
grpc_slice* bytes_received) {
if (client != nullptr && client->vtable != nullptr &&
client->vtable->server_start != nullptr) {
- return client->vtable->server_start(client, event, bytes_received);
+ return client->vtable->server_start(client, bytes_received);
}
gpr_log(GPR_ERROR,
"client or client->vtable has not been initialized properly");
@@ -301,11 +577,10 @@ tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
}
tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
- alts_tsi_event* event,
grpc_slice* bytes_received) {
if (client != nullptr && client->vtable != nullptr &&
client->vtable->next != nullptr) {
- return client->vtable->next(client, event, bytes_received);
+ return client->vtable->next(client, bytes_received);
}
gpr_log(GPR_ERROR,
"client or client->vtable has not been initialized properly");
@@ -319,11 +594,22 @@ void alts_handshaker_client_shutdown(alts_handshaker_client* client) {
}
}
-void alts_handshaker_client_destroy(alts_handshaker_client* client) {
- if (client != nullptr) {
- if (client->vtable != nullptr && client->vtable->destruct != nullptr) {
- client->vtable->destruct(client);
+void alts_handshaker_client_destroy(alts_handshaker_client* c) {
+ if (c != nullptr) {
+ if (c->vtable != nullptr && c->vtable->destruct != nullptr) {
+ c->vtable->destruct(c);
}
+ alts_grpc_handshaker_client* client =
+ reinterpret_cast<alts_grpc_handshaker_client*>(c);
+ grpc_byte_buffer_destroy(client->send_buffer);
+ grpc_byte_buffer_destroy(client->recv_buffer);
+ client->send_buffer = nullptr;
+ client->recv_buffer = nullptr;
+ grpc_metadata_array_destroy(&client->recv_initial_metadata);
+ grpc_slice_unref_internal(client->recv_bytes);
+ grpc_slice_unref_internal(client->target_name);
+ grpc_alts_credentials_options_destroy(client->options);
+ gpr_free(client->buffer);
gpr_free(client);
}
}
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.h b/src/core/tsi/alts/handshaker/alts_handshaker_client.h
index 8dd8fe440d..4b489875f3 100644
--- a/src/core/tsi/alts/handshaker/alts_handshaker_client.h
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.h
@@ -21,16 +21,24 @@
#include <grpc/support/port_platform.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
#include <grpc/grpc.h>
-#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/pollset_set.h"
#define ALTS_SERVICE_METHOD "/grpc.gcp.HandshakerService/DoHandshake"
#define ALTS_APPLICATION_PROTOCOL "grpc"
#define ALTS_RECORD_PROTOCOL "ALTSRP_GCM_AES128_REKEY"
+#define ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING "lame"
const size_t kAltsAes128GcmRekeyKeyLength = 44;
+typedef struct alts_tsi_handshaker alts_tsi_handshaker;
/**
* A ALTS handshaker client interface. It is used to communicate with
* ALTS handshaker service by scheduling a handshaker request that could be one
@@ -41,63 +49,52 @@ typedef struct alts_handshaker_client alts_handshaker_client;
/* A function that makes the grpc call to the handshaker service. */
typedef grpc_call_error (*alts_grpc_caller)(grpc_call* call, const grpc_op* ops,
- size_t nops, void* tag);
+ size_t nops, grpc_closure* tag);
/* V-table for ALTS handshaker client operations. */
typedef struct alts_handshaker_client_vtable {
- tsi_result (*client_start)(alts_handshaker_client* client,
- alts_tsi_event* event);
+ tsi_result (*client_start)(alts_handshaker_client* client);
tsi_result (*server_start)(alts_handshaker_client* client,
- alts_tsi_event* event, grpc_slice* bytes_received);
- tsi_result (*next)(alts_handshaker_client* client, alts_tsi_event* event,
+ grpc_slice* bytes_received);
+ tsi_result (*next)(alts_handshaker_client* client,
grpc_slice* bytes_received);
void (*shutdown)(alts_handshaker_client* client);
void (*destruct)(alts_handshaker_client* client);
} alts_handshaker_client_vtable;
-struct alts_handshaker_client {
- const alts_handshaker_client_vtable* vtable;
-};
-
/**
* This method schedules a client_start handshaker request to ALTS handshaker
* service.
*
* - client: ALTS handshaker client instance.
- * - event: ALTS TSI event instance.
*
* It returns TSI_OK on success and an error status code on failure.
*/
-tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
- alts_tsi_event* event);
+tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client);
/**
* This method schedules a server_start handshaker request to ALTS handshaker
* service.
*
* - client: ALTS handshaker client instance.
- * - event: ALTS TSI event instance.
* - bytes_received: bytes in out_frames returned from the peer's handshaker
* response.
*
* It returns TSI_OK on success and an error status code on failure.
*/
tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
- alts_tsi_event* event,
grpc_slice* bytes_received);
/**
* This method schedules a next handshaker request to ALTS handshaker service.
*
* - client: ALTS handshaker client instance.
- * - event: ALTS TSI event instance.
* - bytes_received: bytes in out_frames returned from the peer's handshaker
* response.
*
* It returns TSI_OK on success and an error status code on failure.
*/
tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
- alts_tsi_event* event,
grpc_slice* bytes_received);
/**
@@ -110,38 +107,51 @@ tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
void alts_handshaker_client_shutdown(alts_handshaker_client* client);
/**
- * This method destroys a ALTS handshaker client.
+ * This method destroys an ALTS handshaker client.
*
- * - client: a ALTS handshaker client instance.
+ * - client: an ALTS handshaker client instance.
*/
void alts_handshaker_client_destroy(alts_handshaker_client* client);
/**
- * This method creates a ALTS handshaker client.
+ * This method creates an ALTS handshaker client.
*
+ * - handshaker: ALTS TSI handshaker to which the created handshaker client
+ * belongs to.
* - channel: grpc channel to ALTS handshaker service.
- * - queue: grpc completion queue.
* - handshaker_service_url: address of ALTS handshaker service in the format of
* "host:port".
- *
- * It returns the created ALTS handshaker client on success, and NULL on
- * failure.
+ * - interested_parties: set of pollsets interested in this connection.
+ * - options: ALTS credentials options containing information passed from TSI
+ * caller (e.g., rpc protocol versions)
+ * - target_name: the name of the endpoint that the channel is connecting to,
+ * and will be used for secure naming check
+ * - grpc_cb: gRPC provided callbacks passed from TSI handshaker.
+ * - cb: callback to be executed when tsi_handshaker_next API compltes.
+ * - user_data: argument passed to cb.
+ * - vtable_for_testing: ALTS handshaker client vtable instance used for
+ * testing purpose.
+ * - is_client: a boolean value indicating if the created handshaker client is
+ * used at the client (is_client = true) or server (is_client = false) side. It
+ * returns the created ALTS handshaker client on success, and NULL on failure.
*/
alts_handshaker_client* alts_grpc_handshaker_client_create(
- grpc_channel* channel, grpc_completion_queue* queue,
- const char* handshaker_service_url);
-
-namespace grpc_core {
-namespace internal {
+ alts_tsi_handshaker* handshaker, grpc_channel* channel,
+ const char* handshaker_service_url, grpc_pollset_set* interested_parties,
+ grpc_alts_credentials_options* options, grpc_slice target_name,
+ grpc_iomgr_cb_func grpc_cb, tsi_handshaker_on_next_done_cb cb,
+ void* user_data, alts_handshaker_client_vtable* vtable_for_testing,
+ bool is_client);
/**
- * Unsafe, use for testing only. It allows the caller to change the way that
- * GRPC calls are made to the handshaker service.
+ * This method handles handshaker response returned from ALTS handshaker
+ * service. Note that the only reason the API is exposed is that it is used in
+ * alts_shared_resources.cc.
+ *
+ * - client: an ALTS handshaker client instance.
+ * - is_ok: a boolean value indicating if the handshaker response is ok to read.
*/
-void alts_handshaker_client_set_grpc_caller_for_testing(
- alts_handshaker_client* client, alts_grpc_caller caller);
-
-} // namespace internal
-} // namespace grpc_core
+void alts_handshaker_client_handle_response(alts_handshaker_client* client,
+ bool is_ok);
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H */
diff --git a/src/core/tsi/alts/handshaker/alts_shared_resource.cc b/src/core/tsi/alts/handshaker/alts_shared_resource.cc
new file mode 100644
index 0000000000..3501257f05
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_shared_resource.cc
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+
+static alts_shared_resource_dedicated g_alts_resource_dedicated;
+
+alts_shared_resource_dedicated* grpc_alts_get_shared_resource_dedicated(void) {
+ return &g_alts_resource_dedicated;
+}
+
+static void thread_worker(void* arg) {
+ while (true) {
+ grpc_event event =
+ grpc_completion_queue_next(g_alts_resource_dedicated.cq,
+ gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
+ GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT);
+ if (event.type == GRPC_QUEUE_SHUTDOWN) {
+ break;
+ }
+ GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
+ alts_handshaker_client* client =
+ static_cast<alts_handshaker_client*>(event.tag);
+ alts_handshaker_client_handle_response(client, event.success);
+ }
+}
+
+void grpc_alts_shared_resource_dedicated_init() {
+ g_alts_resource_dedicated.cq = nullptr;
+ gpr_mu_init(&g_alts_resource_dedicated.mu);
+}
+
+void grpc_alts_shared_resource_dedicated_start(
+ const char* handshaker_service_url) {
+ gpr_mu_lock(&g_alts_resource_dedicated.mu);
+ if (g_alts_resource_dedicated.cq == nullptr) {
+ g_alts_resource_dedicated.channel =
+ grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr);
+ g_alts_resource_dedicated.cq =
+ grpc_completion_queue_create_for_next(nullptr);
+ g_alts_resource_dedicated.thread =
+ grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr);
+ g_alts_resource_dedicated.interested_parties = grpc_pollset_set_create();
+ grpc_pollset_set_add_pollset(g_alts_resource_dedicated.interested_parties,
+ grpc_cq_pollset(g_alts_resource_dedicated.cq));
+ g_alts_resource_dedicated.thread.Start();
+ }
+ gpr_mu_unlock(&g_alts_resource_dedicated.mu);
+}
+
+void grpc_alts_shared_resource_dedicated_shutdown() {
+ if (g_alts_resource_dedicated.cq != nullptr) {
+ grpc_pollset_set_del_pollset(g_alts_resource_dedicated.interested_parties,
+ grpc_cq_pollset(g_alts_resource_dedicated.cq));
+ grpc_completion_queue_shutdown(g_alts_resource_dedicated.cq);
+ g_alts_resource_dedicated.thread.Join();
+ grpc_pollset_set_destroy(g_alts_resource_dedicated.interested_parties);
+ grpc_completion_queue_destroy(g_alts_resource_dedicated.cq);
+ grpc_channel_destroy(g_alts_resource_dedicated.channel);
+ }
+ gpr_mu_destroy(&g_alts_resource_dedicated.mu);
+}
diff --git a/src/core/tsi/alts/handshaker/alts_shared_resource.h b/src/core/tsi/alts/handshaker/alts_shared_resource.h
new file mode 100644
index 0000000000..8ae0089a11
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_shared_resource.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/surface/completion_queue.h"
+
+/**
+ * Main struct containing ALTS shared resources used when
+ * employing the dedicated completion queue and thread.
+ */
+typedef struct alts_shared_resource_dedicated {
+ grpc_core::Thread thread;
+ grpc_completion_queue* cq;
+ grpc_pollset_set* interested_parties;
+ grpc_cq_completion storage;
+ gpr_mu mu;
+ grpc_channel* channel;
+} alts_shared_resource_dedicated;
+
+/* This method returns the address of alts_shared_resource_dedicated
+ * object shared by all TSI handshakes.
+ */
+alts_shared_resource_dedicated* grpc_alts_get_shared_resource_dedicated(void);
+
+/**
+ * This method destroys the alts_shared_resource_dedicated object
+ * shared by all TSI handshakes. The applicaiton is responsible for
+ * invoking the API before calling grpc_shutdown().
+ */
+void grpc_alts_shared_resource_dedicated_shutdown();
+
+/**
+ * This method initializes the alts_shared_resource_dedicated object
+ * shared by all TSI handshakes. The application is responsible for
+ * invoking the API after calling grpc_init();
+ */
+void grpc_alts_shared_resource_dedicated_init();
+
+/**
+ * This method populates various fields of the alts_shared_resource_dedicated
+ * object shared by all TSI handshakes and start the dedicated thread.
+ * The API will be invoked by the caller in a lazy manner. That is,
+ * it will get invoked when ALTS TSI handshake occurs for the first time.
+ */
+void grpc_alts_shared_resource_dedicated_start(
+ const char* handshaker_service_url);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H \
+ */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.cc b/src/core/tsi/alts/handshaker/alts_tsi_event.cc
deleted file mode 100644
index cb36d5ebd1..0000000000
--- a/src/core/tsi/alts/handshaker/alts_tsi_event.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/slice/slice_internal.h"
-
-tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker,
- tsi_handshaker_on_next_done_cb cb,
- void* user_data,
- grpc_alts_credentials_options* options,
- grpc_slice target_name,
- alts_tsi_event** event) {
- if (event == nullptr || handshaker == nullptr || cb == nullptr) {
- gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_event_create()");
- return TSI_INVALID_ARGUMENT;
- }
- alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e)));
- e->handshaker = handshaker;
- e->cb = cb;
- e->user_data = user_data;
- e->options = grpc_alts_credentials_options_copy(options);
- e->target_name = grpc_slice_copy(target_name);
- grpc_metadata_array_init(&e->initial_metadata);
- grpc_metadata_array_init(&e->trailing_metadata);
- *event = e;
- return TSI_OK;
-}
-
-void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok) {
- if (event == nullptr) {
- gpr_log(
- GPR_ERROR,
- "ALTS TSI event is nullptr in alts_tsi_event_dispatch_to_handshaker()");
- return;
- }
- alts_tsi_handshaker_handle_response(event->handshaker, event->recv_buffer,
- event->status, &event->details, event->cb,
- event->user_data, is_ok);
-}
-
-void alts_tsi_event_destroy(alts_tsi_event* event) {
- if (event == nullptr) {
- return;
- }
- grpc_byte_buffer_destroy(event->send_buffer);
- grpc_byte_buffer_destroy(event->recv_buffer);
- grpc_metadata_array_destroy(&event->initial_metadata);
- grpc_metadata_array_destroy(&event->trailing_metadata);
- grpc_slice_unref_internal(event->details);
- grpc_slice_unref_internal(event->target_name);
- grpc_alts_credentials_options_destroy(event->options);
- gpr_free(event);
-}
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.h b/src/core/tsi/alts/handshaker/alts_tsi_event.h
deleted file mode 100644
index 043e75d4a9..0000000000
--- a/src/core/tsi/alts/handshaker/alts_tsi_event.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H
-#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/byte_buffer.h>
-#include <grpc/byte_buffer_reader.h>
-
-#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-/**
- * A ALTS TSI event interface. In asynchronous implementation of
- * tsi_handshaker_next(), the function will exit after scheduling a handshaker
- * request to ALTS handshaker service without waiting for response to return.
- * The event is used to link the scheduled handshaker request with the
- * corresponding response so that enough context information can be inferred
- * from it to handle the response. All APIs in the header are thread-compatible.
- */
-
-/**
- * Main struct for ALTS TSI event. It retains ownership on send_buffer and
- * recv_buffer, but not on handshaker.
- */
-typedef struct alts_tsi_event {
- alts_tsi_handshaker* handshaker;
- grpc_byte_buffer* send_buffer;
- grpc_byte_buffer* recv_buffer;
- grpc_status_code status;
- grpc_slice details;
- grpc_metadata_array initial_metadata;
- grpc_metadata_array trailing_metadata;
- tsi_handshaker_on_next_done_cb cb;
- void* user_data;
- grpc_alts_credentials_options* options;
- grpc_slice target_name;
-} alts_tsi_event;
-
-/**
- * This method creates a ALTS TSI event.
- *
- * - handshaker: ALTS TSI handshaker instance associated with the event to be
- * created. The created event does not own the handshaker instance.
- * - cb: callback function to be called when handling data received from ALTS
- * handshaker service.
- * - user_data: argument to callback function.
- * - options: ALTS credentials options.
- * - target_name: name of endpoint used for secure naming check.
- * - event: address of ALTS TSI event instance to be returned from the method.
- *
- * It returns TSI_OK on success and an error status code on failure.
- */
-tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker,
- tsi_handshaker_on_next_done_cb cb,
- void* user_data,
- grpc_alts_credentials_options* options,
- grpc_slice target_name,
- alts_tsi_event** event);
-
-/**
- * This method dispatches a ALTS TSI event received from the handshaker service,
- * and a boolean flag indicating if the event is valid to read to ALTS TSI
- * handshaker to process. It is called by TSI thread.
- *
- * - event: ALTS TSI event instance.
- * - is_ok: a boolean value indicating if the event is valid to read.
- */
-void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok);
-
-/**
- * This method destroys the ALTS TSI event.
- */
-void alts_tsi_event_destroy(alts_tsi_event* event);
-
-#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
index dfdd659b87..1b7e58d3ce 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
@@ -26,34 +26,34 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
-#include "src/core/tsi/alts_transport_security.h"
-
-#define TSI_ALTS_INITIAL_BUFFER_SIZE 256
-
-static alts_shared_resource* kSharedResource = alts_get_shared_resource();
/* Main struct for ALTS TSI handshaker. */
-typedef struct alts_tsi_handshaker {
+struct alts_tsi_handshaker {
tsi_handshaker base;
alts_handshaker_client* client;
- grpc_slice recv_bytes;
grpc_slice target_name;
- unsigned char* buffer;
- size_t buffer_size;
bool is_client;
bool has_sent_start_message;
+ bool has_created_handshaker_client;
+ char* handshaker_service_url;
+ grpc_pollset_set* interested_parties;
grpc_alts_credentials_options* options;
-} alts_tsi_handshaker;
+ alts_handshaker_client_vtable* client_vtable_for_testing;
+ grpc_channel* channel;
+};
/* Main struct for ALTS TSI handshaker result. */
typedef struct alts_tsi_handshaker_result {
@@ -193,9 +193,9 @@ static const tsi_handshaker_result_vtable result_vtable = {
handshaker_result_create_frame_protector,
handshaker_result_get_unused_bytes, handshaker_result_destroy};
-static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp,
- bool is_client,
- tsi_handshaker_result** self) {
+tsi_result alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp* resp,
+ bool is_client,
+ tsi_handshaker_result** self) {
if (self == nullptr || resp == nullptr) {
gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()");
return TSI_INVALID_ARGUMENT;
@@ -234,6 +234,27 @@ static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp,
return TSI_OK;
}
+/* gRPC provided callback used when gRPC thread model is applied. */
+static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
+ alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg);
+ if (client == nullptr) {
+ gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr");
+ return;
+ }
+ alts_handshaker_client_handle_response(client, true);
+}
+
+/* gRPC provided callback used when dedicatd CQ and thread are used.
+ * It serves to safely bring the control back to application. */
+static void on_handshaker_service_resp_recv_dedicated(void* arg,
+ grpc_error* error) {
+ alts_shared_resource_dedicated* resource =
+ grpc_alts_get_shared_resource_dedicated();
+ grpc_cq_end_op(resource->cq, arg, GRPC_ERROR_NONE,
+ [](void* done_arg, grpc_cq_completion* storage) {}, nullptr,
+ &resource->storage);
+}
+
static tsi_result handshaker_next(
tsi_handshaker* self, const unsigned char* received_bytes,
size_t received_bytes_size, const unsigned char** bytes_to_send,
@@ -250,12 +271,36 @@ static tsi_result handshaker_next(
alts_tsi_handshaker* handshaker =
reinterpret_cast<alts_tsi_handshaker*>(self);
tsi_result ok = TSI_OK;
- alts_tsi_event* event = nullptr;
- ok = alts_tsi_event_create(handshaker, cb, user_data, handshaker->options,
- handshaker->target_name, &event);
- if (ok != TSI_OK) {
- gpr_log(GPR_ERROR, "Failed to create ALTS TSI event");
- return ok;
+ if (!handshaker->has_created_handshaker_client) {
+ if (handshaker->channel == nullptr) {
+ grpc_alts_shared_resource_dedicated_start(
+ handshaker->handshaker_service_url);
+ handshaker->interested_parties =
+ grpc_alts_get_shared_resource_dedicated()->interested_parties;
+ GPR_ASSERT(handshaker->interested_parties != nullptr);
+ }
+ grpc_iomgr_cb_func grpc_cb = handshaker->channel == nullptr
+ ? on_handshaker_service_resp_recv_dedicated
+ : on_handshaker_service_resp_recv;
+ grpc_channel* channel =
+ handshaker->channel == nullptr
+ ? grpc_alts_get_shared_resource_dedicated()->channel
+ : handshaker->channel;
+ handshaker->client = alts_grpc_handshaker_client_create(
+ handshaker, channel, handshaker->handshaker_service_url,
+ handshaker->interested_parties, handshaker->options,
+ handshaker->target_name, grpc_cb, cb, user_data,
+ handshaker->client_vtable_for_testing, handshaker->is_client);
+ if (handshaker->client == nullptr) {
+ gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client");
+ return TSI_FAILED_PRECONDITION;
+ }
+ handshaker->has_created_handshaker_client = true;
+ }
+ if (handshaker->channel == nullptr &&
+ handshaker->client_vtable_for_testing == nullptr) {
+ GPR_ASSERT(grpc_cq_begin_op(grpc_alts_get_shared_resource_dedicated()->cq,
+ handshaker->client));
}
grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0)
? grpc_empty_slice()
@@ -264,16 +309,11 @@ static tsi_result handshaker_next(
received_bytes_size);
if (!handshaker->has_sent_start_message) {
ok = handshaker->is_client
- ? alts_handshaker_client_start_client(handshaker->client, event)
- : alts_handshaker_client_start_server(handshaker->client, event,
- &slice);
+ ? alts_handshaker_client_start_client(handshaker->client)
+ : alts_handshaker_client_start_server(handshaker->client, &slice);
handshaker->has_sent_start_message = true;
} else {
- if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) {
- grpc_slice_unref_internal(handshaker->recv_bytes);
- }
- handshaker->recv_bytes = grpc_slice_ref(slice);
- ok = alts_handshaker_client_next(handshaker->client, event, &slice);
+ ok = alts_handshaker_client_next(handshaker->client, &slice);
}
grpc_slice_unref_internal(slice);
if (ok != TSI_OK) {
@@ -283,6 +323,22 @@ static tsi_result handshaker_next(
return TSI_ASYNC;
}
+/*
+ * This API will be invoked by a non-gRPC application, and an ExecCtx needs
+ * to be explicitly created in order to invoke ALTS handshaker client API's
+ * that assumes the caller is inside gRPC core.
+ */
+static tsi_result handshaker_next_dedicated(
+ tsi_handshaker* self, const unsigned char* received_bytes,
+ size_t received_bytes_size, const unsigned char** bytes_to_send,
+ size_t* bytes_to_send_size, tsi_handshaker_result** result,
+ tsi_handshaker_on_next_done_cb cb, void* user_data) {
+ grpc_core::ExecCtx exec_ctx;
+ return handshaker_next(self, received_bytes, received_bytes_size,
+ bytes_to_send, bytes_to_send_size, result, cb,
+ user_data);
+}
+
static void handshaker_shutdown(tsi_handshaker* self) {
GPR_ASSERT(self != nullptr);
if (self->handshake_shutdown) {
@@ -300,10 +356,12 @@ static void handshaker_destroy(tsi_handshaker* self) {
alts_tsi_handshaker* handshaker =
reinterpret_cast<alts_tsi_handshaker*>(self);
alts_handshaker_client_destroy(handshaker->client);
- grpc_slice_unref_internal(handshaker->recv_bytes);
grpc_slice_unref_internal(handshaker->target_name);
grpc_alts_credentials_options_destroy(handshaker->options);
- gpr_free(handshaker->buffer);
+ if (handshaker->channel != nullptr) {
+ grpc_channel_destroy(handshaker->channel);
+ }
+ gpr_free(handshaker->handshaker_service_url);
gpr_free(handshaker);
}
@@ -313,36 +371,19 @@ static const tsi_handshaker_vtable handshaker_vtable = {
nullptr, handshaker_destroy,
handshaker_next, handshaker_shutdown};
-static void thread_worker(void* arg) {
- while (true) {
- grpc_event event = grpc_completion_queue_next(
- kSharedResource->cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
- GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT);
- if (event.type == GRPC_QUEUE_SHUTDOWN) {
- /* signal alts_tsi_shutdown() to destroy completion queue. */
- grpc_tsi_alts_signal_for_cq_destroy();
- break;
- }
- /* event.type == GRPC_OP_COMPLETE. */
- alts_tsi_event* alts_event = static_cast<alts_tsi_event*>(event.tag);
- alts_tsi_event_dispatch_to_handshaker(alts_event, event.success);
- alts_tsi_event_destroy(alts_event);
- }
-}
-
-static void init_shared_resources(const char* handshaker_service_url) {
- GPR_ASSERT(handshaker_service_url != nullptr);
- gpr_mu_lock(&kSharedResource->mu);
- if (kSharedResource->channel == nullptr) {
- gpr_cv_init(&kSharedResource->cv);
- kSharedResource->channel =
- grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr);
- kSharedResource->cq = grpc_completion_queue_create_for_next(nullptr);
- kSharedResource->thread =
- grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr);
- kSharedResource->thread.Start();
- }
- gpr_mu_unlock(&kSharedResource->mu);
+static const tsi_handshaker_vtable handshaker_vtable_dedicated = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ handshaker_destroy,
+ handshaker_next_dedicated,
+ handshaker_shutdown};
+
+bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker) {
+ GPR_ASSERT(handshaker != nullptr);
+ return handshaker->base.handshake_shutdown;
}
tsi_result alts_tsi_handshaker_create(
@@ -354,40 +395,33 @@ tsi_result alts_tsi_handshaker_create(
gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()");
return TSI_INVALID_ARGUMENT;
}
- init_shared_resources(handshaker_service_url);
- alts_handshaker_client* client = alts_grpc_handshaker_client_create(
- kSharedResource->channel, kSharedResource->cq, handshaker_service_url);
- if (client == nullptr) {
- gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client");
- return TSI_FAILED_PRECONDITION;
- }
alts_tsi_handshaker* handshaker =
static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker)));
- handshaker->client = client;
- handshaker->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE;
- handshaker->buffer =
- static_cast<unsigned char*>(gpr_zalloc(handshaker->buffer_size));
+ bool use_dedicated_cq = interested_parties == nullptr;
+ handshaker->client = nullptr;
handshaker->is_client = is_client;
handshaker->has_sent_start_message = false;
handshaker->target_name = target_name == nullptr
? grpc_empty_slice()
: grpc_slice_from_static_string(target_name);
+ handshaker->interested_parties = interested_parties;
+ handshaker->has_created_handshaker_client = false;
+ handshaker->handshaker_service_url = gpr_strdup(handshaker_service_url);
handshaker->options = grpc_alts_credentials_options_copy(options);
- handshaker->base.vtable = &handshaker_vtable;
+ handshaker->base.vtable =
+ use_dedicated_cq ? &handshaker_vtable_dedicated : &handshaker_vtable;
+ handshaker->channel =
+ use_dedicated_cq
+ ? nullptr
+ : grpc_insecure_channel_create(handshaker->handshaker_service_url,
+ nullptr, nullptr);
*self = &handshaker->base;
return TSI_OK;
}
-static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) {
- GPR_ASSERT(resp != nullptr);
- if (resp->has_result) {
- return true;
- }
- return false;
-}
-
-static void set_unused_bytes(tsi_handshaker_result* self,
- grpc_slice* recv_bytes, size_t bytes_consumed) {
+void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* self,
+ grpc_slice* recv_bytes,
+ size_t bytes_consumed) {
GPR_ASSERT(recv_bytes != nullptr && self != nullptr);
if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) {
return;
@@ -402,81 +436,6 @@ static void set_unused_bytes(tsi_handshaker_result* self,
result->unused_bytes_size);
}
-void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker,
- grpc_byte_buffer* recv_buffer,
- grpc_status_code status,
- grpc_slice* details,
- tsi_handshaker_on_next_done_cb cb,
- void* user_data, bool is_ok) {
- /* Invalid input check. */
- if (cb == nullptr) {
- gpr_log(GPR_ERROR,
- "cb is nullptr in alts_tsi_handshaker_handle_response()");
- return;
- }
- if (handshaker == nullptr || recv_buffer == nullptr) {
- gpr_log(GPR_ERROR,
- "Invalid arguments to alts_tsi_handshaker_handle_response()");
- cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
- return;
- }
- if (handshaker->base.handshake_shutdown) {
- gpr_log(GPR_ERROR, "TSI handshake shutdown");
- cb(TSI_HANDSHAKE_SHUTDOWN, user_data, nullptr, 0, nullptr);
- return;
- }
- /* Failed grpc call check. */
- if (!is_ok || status != GRPC_STATUS_OK) {
- gpr_log(GPR_ERROR, "grpc call made to handshaker service failed");
- if (details != nullptr) {
- char* error_details = grpc_slice_to_c_string(*details);
- gpr_log(GPR_ERROR, "error details:%s", error_details);
- gpr_free(error_details);
- }
- cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
- return;
- }
- grpc_gcp_handshaker_resp* resp =
- alts_tsi_utils_deserialize_response(recv_buffer);
- /* Invalid handshaker response check. */
- if (resp == nullptr) {
- gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed");
- cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr);
- return;
- }
- grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg);
- unsigned char* bytes_to_send = nullptr;
- size_t bytes_to_send_size = 0;
- if (slice != nullptr) {
- bytes_to_send_size = GRPC_SLICE_LENGTH(*slice);
- while (bytes_to_send_size > handshaker->buffer_size) {
- handshaker->buffer_size *= 2;
- handshaker->buffer = static_cast<unsigned char*>(
- gpr_realloc(handshaker->buffer, handshaker->buffer_size));
- }
- memcpy(handshaker->buffer, GRPC_SLICE_START_PTR(*slice),
- bytes_to_send_size);
- bytes_to_send = handshaker->buffer;
- }
- tsi_handshaker_result* result = nullptr;
- if (is_handshake_finished_properly(resp)) {
- create_handshaker_result(resp, handshaker->is_client, &result);
- set_unused_bytes(result, &handshaker->recv_bytes, resp->bytes_consumed);
- }
- grpc_status_code code = static_cast<grpc_status_code>(resp->status.code);
- if (code != GRPC_STATUS_OK) {
- grpc_slice* details = static_cast<grpc_slice*>(resp->status.details.arg);
- if (details != nullptr) {
- char* error_details = grpc_slice_to_c_string(*details);
- gpr_log(GPR_ERROR, "Error from handshaker service:%s", error_details);
- gpr_free(error_details);
- }
- }
- grpc_gcp_handshaker_resp_destroy(resp);
- cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send,
- bytes_to_send_size, result);
-}
-
namespace grpc_core {
namespace internal {
@@ -486,29 +445,16 @@ bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
return handshaker->has_sent_start_message;
}
-bool alts_tsi_handshaker_get_is_client_for_testing(
- alts_tsi_handshaker* handshaker) {
+void alts_tsi_handshaker_set_client_vtable_for_testing(
+ alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable) {
GPR_ASSERT(handshaker != nullptr);
- return handshaker->is_client;
-}
-
-void alts_tsi_handshaker_set_recv_bytes_for_testing(
- alts_tsi_handshaker* handshaker, grpc_slice* slice) {
- GPR_ASSERT(handshaker != nullptr && slice != nullptr);
- handshaker->recv_bytes = grpc_slice_ref(*slice);
+ handshaker->client_vtable_for_testing = vtable;
}
-grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing(
+bool alts_tsi_handshaker_get_is_client_for_testing(
alts_tsi_handshaker* handshaker) {
GPR_ASSERT(handshaker != nullptr);
- return handshaker->recv_bytes;
-}
-
-void alts_tsi_handshaker_set_client_for_testing(
- alts_tsi_handshaker* handshaker, alts_handshaker_client* client) {
- GPR_ASSERT(handshaker != nullptr && client != nullptr);
- alts_handshaker_client_destroy(handshaker->client);
- handshaker->client = client;
+ return handshaker->is_client;
}
alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing(
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
index 48ce69b1da..32f94bc9d3 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
@@ -25,7 +25,8 @@
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
-#include "src/core/tsi/alts_transport_security.h"
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h"
#include "src/core/tsi/transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
@@ -35,10 +36,6 @@
const size_t kTsiAltsNumOfPeerProperties = 3;
-/**
- * Main struct for ALTS TSI handshaker. All APIs in the header are
- * thread-comptabile.
- */
typedef struct alts_tsi_handshaker alts_tsi_handshaker;
/**
@@ -56,7 +53,9 @@ typedef struct alts_tsi_handshaker alts_tsi_handshaker;
* - self: address of ALTS TSI handshaker instance to be returned from the
* method.
*
- * It returns TSI_OK on success and an error status code on failure.
+ * It returns TSI_OK on success and an error status code on failure. Note that
+ * if interested_parties is nullptr, a dedicated TSI thread will be created and
+ * used.
*/
tsi_result alts_tsi_handshaker_create(
const grpc_alts_credentials_options* options, const char* target_name,
@@ -64,23 +63,32 @@ tsi_result alts_tsi_handshaker_create(
grpc_pollset_set* interested_parties, tsi_handshaker** self);
/**
- * This method handles handshaker response returned from ALTS handshaker
- * service.
+ * This method creates an ALTS TSI handshaker result instance.
*
- * - handshaker: ALTS TSI handshaker instance.
- * - recv_buffer: buffer holding data received from the handshaker service.
- * - status: status of the grpc call made to the handshaker service.
- * - details: error details of the grpc call made to the handshaker service.
- * - cb: callback function of ALTS TSI event.
- * - user_data: argument of callback function.
- * - is_ok: a boolean value indicating if the handshaker response is ok to read.
+ * - resp: data received from the handshaker service.
+ * - is_client: a boolean value indicating if the result belongs to a
+ * client or not.
+ * - result: address of ALTS TSI handshaker result instance.
+ */
+tsi_result alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp* resp,
+ bool is_client,
+ tsi_handshaker_result** result);
+
+/**
+ * This method sets unused bytes of ALTS TSI handshaker result instance.
*
+ * - result: an ALTS TSI handshaker result instance.
+ * - recv_bytes: data received from the handshaker service.
+ * - bytes_consumed: size of data consumed by the handshaker service.
+ */
+void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* result,
+ grpc_slice* recv_bytes,
+ size_t bytes_consumed);
+
+/**
+ * This method returns a boolean value indicating if an ALTS TSI handshaker
+ * has been shutdown or not.
*/
-void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker,
- grpc_byte_buffer* recv_buffer,
- grpc_status_code status,
- grpc_slice* details,
- tsi_handshaker_on_next_done_cb cb,
- void* user_data, bool is_ok);
+bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker);
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
index 9612071407..ec2616e95f 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
@@ -27,27 +27,55 @@ namespace grpc_core {
namespace internal {
/**
- * Unsafe, use for testing only. It allows the caller to change the way the
- * ALTS TSI handshaker schedules handshaker requests.
- */
-void alts_tsi_handshaker_set_client_for_testing(alts_tsi_handshaker* handshaker,
- alts_handshaker_client* client);
+ * Unsafe, use for testing only. */
alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing(
alts_tsi_handshaker* handshaker);
-/* For testing only. */
bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
alts_tsi_handshaker* handshaker);
+void alts_tsi_handshaker_set_client_vtable_for_testing(
+ alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable);
+
bool alts_tsi_handshaker_get_is_client_for_testing(
alts_tsi_handshaker* handshaker);
-void alts_tsi_handshaker_set_recv_bytes_for_testing(
- alts_tsi_handshaker* handshaker, grpc_slice* slice);
+void alts_handshaker_client_set_grpc_caller_for_testing(
+ alts_handshaker_client* client, alts_grpc_caller caller);
-grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing(
- alts_tsi_handshaker* handshaker);
+grpc_byte_buffer* alts_handshaker_client_get_send_buffer_for_testing(
+ alts_handshaker_client* client);
+
+grpc_byte_buffer** alts_handshaker_client_get_recv_buffer_addr_for_testing(
+ alts_handshaker_client* client);
+
+grpc_metadata_array* alts_handshaker_client_get_initial_metadata_for_testing(
+ alts_handshaker_client* client);
+
+void alts_handshaker_client_set_recv_bytes_for_testing(
+ alts_handshaker_client* client, grpc_slice* recv_bytes);
+
+void alts_handshaker_client_check_fields_for_testing(
+ alts_handshaker_client* client, tsi_handshaker_on_next_done_cb cb,
+ void* user_data, bool has_sent_start_message, grpc_slice* recv_bytes);
+
+void alts_handshaker_client_set_fields_for_testing(
+ alts_handshaker_client* client, alts_tsi_handshaker* handshaker,
+ tsi_handshaker_on_next_done_cb cb, void* user_data,
+ grpc_byte_buffer* recv_buffer, grpc_status_code status);
+
+void alts_handshaker_client_set_vtable_for_testing(
+ alts_handshaker_client* client, alts_handshaker_client_vtable* vtable);
+
+alts_tsi_handshaker* alts_handshaker_client_get_handshaker_for_testing(
+ alts_handshaker_client* client);
+
+void alts_handshaker_client_set_cb_for_testing(
+ alts_handshaker_client* client, tsi_handshaker_on_next_done_cb cb);
+
+grpc_closure* alts_handshaker_client_get_closure_for_testing(
+ alts_handshaker_client* client);
} // namespace internal
} // namespace grpc_core
diff --git a/src/core/tsi/alts_transport_security.cc b/src/core/tsi/alts_transport_security.cc
deleted file mode 100644
index dac23bbf7a..0000000000
--- a/src/core/tsi/alts_transport_security.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/tsi/alts_transport_security.h"
-
-#include <string.h>
-
-static alts_shared_resource g_alts_resource;
-
-alts_shared_resource* alts_get_shared_resource(void) {
- return &g_alts_resource;
-}
-
-static void grpc_tsi_alts_wait_for_cq_drain() {
- gpr_mu_lock(&g_alts_resource.mu);
- while (!g_alts_resource.is_cq_drained) {
- gpr_cv_wait(&g_alts_resource.cv, &g_alts_resource.mu,
- gpr_inf_future(GPR_CLOCK_REALTIME));
- }
- gpr_mu_unlock(&g_alts_resource.mu);
-}
-
-void grpc_tsi_alts_signal_for_cq_destroy() {
- gpr_mu_lock(&g_alts_resource.mu);
- g_alts_resource.is_cq_drained = true;
- gpr_cv_signal(&g_alts_resource.cv);
- gpr_mu_unlock(&g_alts_resource.mu);
-}
-
-void grpc_tsi_alts_init() {
- g_alts_resource.channel = nullptr;
- g_alts_resource.cq = nullptr;
- g_alts_resource.is_cq_drained = false;
- gpr_mu_init(&g_alts_resource.mu);
- gpr_cv_init(&g_alts_resource.cv);
-}
-
-void grpc_tsi_alts_shutdown() {
- if (g_alts_resource.cq != nullptr) {
- grpc_completion_queue_shutdown(g_alts_resource.cq);
- grpc_tsi_alts_wait_for_cq_drain();
- grpc_completion_queue_destroy(g_alts_resource.cq);
- grpc_channel_destroy(g_alts_resource.channel);
- g_alts_resource.thread.Join();
- }
- gpr_cv_destroy(&g_alts_resource.cv);
- gpr_mu_destroy(&g_alts_resource.mu);
-}
diff --git a/src/core/tsi/alts_transport_security.h b/src/core/tsi/alts_transport_security.h
deleted file mode 100644
index d6b8e11137..0000000000
--- a/src/core/tsi/alts_transport_security.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H
-#define GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/sync.h>
-
-#include "src/core/lib/gprpp/thd.h"
-
-typedef struct alts_shared_resource {
- grpc_core::Thread thread;
- grpc_channel* channel;
- grpc_completion_queue* cq;
- gpr_mu mu;
- gpr_cv cv;
- bool is_cq_drained;
-} alts_shared_resource;
-
-/* This method returns the address of alts_shared_resource object shared by all
- * TSI handshakes. */
-alts_shared_resource* alts_get_shared_resource(void);
-
-/* This method signals the thread that invokes grpc_tsi_alts_shutdown() to
- * continue with destroying the cq as a part of shutdown process. */
-
-void grpc_tsi_alts_signal_for_cq_destroy(void);
-
-#endif /* GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/transport_security.cc b/src/core/tsi/transport_security.cc
index ca861b52de..078a917bba 100644
--- a/src/core/tsi/transport_security.cc
+++ b/src/core/tsi/transport_security.cc
@@ -213,10 +213,10 @@ tsi_result tsi_handshaker_next(
void tsi_handshaker_shutdown(tsi_handshaker* self) {
if (self == nullptr || self->vtable == nullptr) return;
- self->handshake_shutdown = true;
if (self->vtable->shutdown != nullptr) {
self->vtable->shutdown(self);
}
+ self->handshake_shutdown = true;
}
void tsi_handshaker_destroy(tsi_handshaker* self) {
diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc
index 2cab41b3f5..a31d0b30b1 100644
--- a/src/cpp/client/channel_cc.cc
+++ b/src/cpp/client/channel_cc.cc
@@ -33,6 +33,7 @@
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/rpc_method.h>
@@ -53,14 +54,11 @@ namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
Channel::Channel(
const grpc::string& host, grpc_channel* channel,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators)
: host_(host), c_channel_(channel) {
- auto* vector = interceptor_creators.release();
- if (vector != nullptr) {
- interceptor_creators_ = std::move(*vector);
- }
+ interceptor_creators_ = std::move(interceptor_creators);
g_gli_initializer.summon();
}
@@ -112,9 +110,10 @@ void ChannelResetConnectionBackoff(Channel* channel) {
} // namespace experimental
-internal::Call Channel::CreateCall(const internal::RpcMethod& method,
- ClientContext* context,
- CompletionQueue* cq) {
+internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq,
+ size_t interceptor_pos) {
const bool kRegistered = method.channel_tag() && context->authority().empty();
grpc_call* c_call = nullptr;
if (kRegistered) {
@@ -146,18 +145,28 @@ internal::Call Channel::CreateCall(const internal::RpcMethod& method,
}
}
grpc_census_call_set_context(c_call, context->census_context());
+
+ // ClientRpcInfo should be set before call because set_call also checks
+ // whether the call has been cancelled, and if the call was cancelled, we
+ // should notify the interceptors too/
+ auto* info =
+ context->set_client_rpc_info(method.name(), method.method_type(), this,
+ interceptor_creators_, interceptor_pos);
context->set_call(c_call, shared_from_this());
- return internal::Call(c_call, this, cq);
+
+ return internal::Call(c_call, this, cq, info);
+}
+
+internal::Call Channel::CreateCall(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq) {
+ return CreateCallInternal(method, context, cq, 0);
}
void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) {
- static const size_t MAX_OPS = 8;
- size_t nops = 0;
- grpc_op cops[MAX_OPS];
- ops->FillOps(call->call(), cops, &nops);
- GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops,
- ops->cq_tag(), nullptr));
+ ops->FillOps(
+ call); // Make a copy of call. It's fine since Call just has pointers
}
void* Channel::RegisterMethod(const char* method) {
@@ -219,7 +228,7 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
static void Run(grpc_experimental_completion_queue_functor* cb, int) {
auto* callback = static_cast<ShutdownCallback*>(cb);
delete callback->cq_;
- grpc_core::Delete(callback);
+ delete callback;
}
private:
@@ -232,7 +241,7 @@ CompletionQueue* Channel::CallbackCQ() {
// if there is no explicit per-channel CQ registered
std::lock_guard<std::mutex> l(mu_);
if (callback_cq_ == nullptr) {
- auto* shutdown_callback = grpc_core::New<ShutdownCallback>();
+ auto* shutdown_callback = new ShutdownCallback;
callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
shutdown_callback});
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 07a04e4268..c9ea3e5f83 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -24,6 +24,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpcpp/impl/codegen/interceptor_common.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/server_context.h>
@@ -40,9 +41,10 @@ class DefaultGlobalClientCallbacks final
};
static internal::GrpcLibraryInitializer g_gli_initializer;
-static DefaultGlobalClientCallbacks g_default_client_callbacks;
+static DefaultGlobalClientCallbacks* g_default_client_callbacks =
+ new DefaultGlobalClientCallbacks();
static ClientContext::GlobalCallbacks* g_client_callbacks =
- &g_default_client_callbacks;
+ g_default_client_callbacks;
ClientContext::ClientContext()
: initial_metadata_received_(false),
@@ -86,10 +88,13 @@ void ClientContext::set_call(grpc_call* call,
call_ = call;
channel_ = channel;
if (creds_ && !creds_->ApplyToCall(call_)) {
+ // TODO(yashykt): should interceptors also see this status?
+ SendCancelToInterceptors();
grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
"Failed to set credentials to rpc.", nullptr);
}
if (call_canceled_) {
+ SendCancelToInterceptors();
grpc_call_cancel(call_, nullptr);
}
}
@@ -110,12 +115,20 @@ void ClientContext::set_compression_algorithm(
void ClientContext::TryCancel() {
std::unique_lock<std::mutex> lock(mu_);
if (call_) {
+ SendCancelToInterceptors();
grpc_call_cancel(call_, nullptr);
} else {
call_canceled_ = true;
}
}
+void ClientContext::SendCancelToInterceptors() {
+ internal::CancelInterceptorBatchMethods cancel_methods;
+ for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) {
+ rpc_info_.RunInterceptor(&cancel_methods, i);
+ }
+}
+
grpc::string ClientContext::peer() const {
grpc::string peer;
if (call_) {
@@ -127,9 +140,9 @@ grpc::string ClientContext::peer() const {
}
void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
- GPR_ASSERT(g_client_callbacks == &g_default_client_callbacks);
+ GPR_ASSERT(g_client_callbacks == g_default_client_callbacks);
GPR_ASSERT(client_callbacks != nullptr);
- GPR_ASSERT(client_callbacks != &g_default_client_callbacks);
+ GPR_ASSERT(client_callbacks != g_default_client_callbacks);
g_client_callbacks = client_callbacks;
}
diff --git a/src/cpp/client/client_interceptor.cc b/src/cpp/client/client_interceptor.cc
new file mode 100644
index 0000000000..3a5cac9830
--- /dev/null
+++ b/src/cpp/client/client_interceptor.cc
@@ -0,0 +1,34 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpcpp/impl/codegen/client_interceptor.h>
+
+namespace grpc {
+
+namespace internal {
+experimental::ClientInterceptorFactoryInterface*
+ g_global_client_interceptor_factory = nullptr;
+}
+
+namespace experimental {
+void RegisterGlobalClientInterceptorFactory(
+ ClientInterceptorFactoryInterface* factory) {
+ internal::g_global_client_interceptor_factory = factory;
+}
+} // namespace experimental
+} // namespace grpc
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index efdff6c265..457daa674c 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -39,13 +39,14 @@ std::shared_ptr<Channel> CreateCustomChannel(
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args) {
GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds.
- return creds
- ? creds->CreateChannel(target, args)
- : CreateChannelInternal("",
- grpc_lame_client_channel_create(
- nullptr, GRPC_STATUS_INVALID_ARGUMENT,
- "Invalid credentials."),
- nullptr);
+ return creds ? creds->CreateChannel(target, args)
+ : CreateChannelInternal(
+ "",
+ grpc_lame_client_channel_create(
+ nullptr, GRPC_STATUS_INVALID_ARGUMENT,
+ "Invalid credentials."),
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
namespace experimental {
@@ -64,17 +65,18 @@ std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
- return creds
- ? creds->CreateChannelWithInterceptors(
- target, args, std::move(interceptor_creators))
- : CreateChannelInternal("",
- grpc_lame_client_channel_create(
- nullptr, GRPC_STATUS_INVALID_ARGUMENT,
- "Invalid credentials."),
- nullptr);
+ return creds ? creds->CreateChannelWithInterceptors(
+ target, args, std::move(interceptor_creators))
+ : CreateChannelInternal(
+ "",
+ grpc_lame_client_channel_create(
+ nullptr, GRPC_STATUS_INVALID_ARGUMENT,
+ "Invalid credentials."),
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
} // namespace experimental
diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc
index 313d682aae..a0efb97f7e 100644
--- a/src/cpp/client/create_channel_internal.cc
+++ b/src/cpp/client/create_channel_internal.cc
@@ -26,8 +26,8 @@ namespace grpc {
std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
return std::shared_ptr<Channel>(
new Channel(host, c_channel, std::move(interceptor_creators)));
diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h
index 512fc22866..a90c92c518 100644
--- a/src/cpp/client/create_channel_internal.h
+++ b/src/cpp/client/create_channel_internal.h
@@ -31,8 +31,8 @@ class Channel;
std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace grpc
diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc
index 8d775e7a87..3affc1ef39 100644
--- a/src/cpp/client/create_channel_posix.cc
+++ b/src/cpp/client/create_channel_posix.cc
@@ -34,7 +34,8 @@ std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
init_lib.init();
return CreateChannelInternal(
"", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr),
- nullptr);
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
}
std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
@@ -46,15 +47,16 @@ std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
return CreateChannelInternal(
"",
grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args),
- nullptr);
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
}
namespace experimental {
std::shared_ptr<Channel> CreateCustomInsecureChannelWithInterceptorsFromFd(
const grpc::string& target, int fd, const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
internal::GrpcLibrary init_lib;
init_lib.init();
diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc
index 09a76b428c..b2801764f2 100644
--- a/src/cpp/client/cronet_credentials.cc
+++ b/src/cpp/client/cronet_credentials.cc
@@ -31,7 +31,10 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials {
std::shared_ptr<grpc::Channel> CreateChannel(
const string& target, const grpc::ChannelArguments& args) override {
- return CreateChannelWithInterceptors(target, args, nullptr);
+ return CreateChannelWithInterceptors(
+ target, args,
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
SecureChannelCredentials* AsSecureCredentials() override { return nullptr; }
@@ -39,8 +42,8 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials {
private:
std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
const string& target, const grpc::ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) override {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc
index 87902b26f0..f61c1b5317 100644
--- a/src/cpp/client/generic_stub.cc
+++ b/src/cpp/client/generic_stub.cc
@@ -72,4 +72,13 @@ void GenericStub::experimental_type::UnaryCall(
context, request, response, std::move(on_completion));
}
+void GenericStub::experimental_type::PrepareBidiStreamingCall(
+ ClientContext* context, const grpc::string& method,
+ experimental::ClientBidiReactor<ByteBuffer, ByteBuffer>* reactor) {
+ internal::ClientCallbackReaderWriterFactory<ByteBuffer, ByteBuffer>::Create(
+ stub_->channel_.get(),
+ internal::RpcMethod(method.c_str(), internal::RpcMethod::BIDI_STREAMING),
+ context, reactor);
+}
+
} // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index b816e0c59a..241ce91803 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -32,13 +32,16 @@ class InsecureChannelCredentialsImpl final : public ChannelCredentials {
public:
std::shared_ptr<grpc::Channel> CreateChannel(
const string& target, const grpc::ChannelArguments& args) override {
- return CreateChannelWithInterceptors(target, args, nullptr);
+ return CreateChannelWithInterceptors(
+ target, args,
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
const string& target, const grpc::ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) override {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index d1cd78e755..d0abe441a6 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -36,14 +36,17 @@ SecureChannelCredentials::SecureChannelCredentials(
std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel(
const string& target, const grpc::ChannelArguments& args) {
- return CreateChannelWithInterceptors(target, args, nullptr);
+ return CreateChannelWithInterceptors(
+ target, args,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
}
std::shared_ptr<grpc::Channel>
SecureChannelCredentials::CreateChannelWithInterceptors(
const string& target, const grpc::ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
@@ -228,9 +231,10 @@ int MetadataCredentialsPluginWrapper::GetMetadata(
}
if (w->plugin_->IsBlocking()) {
// Asynchronous return.
- w->thread_pool_->Add(
- std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context,
- cb, user_data, nullptr, nullptr, nullptr, nullptr));
+ w->thread_pool_->Add([w, context, cb, user_data] {
+ w->MetadataCredentialsPluginWrapper::InvokePlugin(
+ context, cb, user_data, nullptr, nullptr, nullptr, nullptr);
+ });
return 0;
} else {
// Synchronous return.
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index bfb6e17ee9..613f1d6dc2 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -42,8 +42,8 @@ class SecureChannelCredentials final : public ChannelCredentials {
private:
std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
const string& target, const grpc::ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) override;
grpc_channel_credentials* const c_creds_;
};
diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc
index 6893201e2e..d93a54aed7 100644
--- a/src/cpp/common/completion_queue_cc.cc
+++ b/src/cpp/common/completion_queue_cc.cc
@@ -60,10 +60,10 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
case GRPC_QUEUE_SHUTDOWN:
return SHUTDOWN;
case GRPC_OP_COMPLETE:
- auto cq_tag = static_cast<internal::CompletionQueueTag*>(ev.tag);
+ auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(ev.tag);
*ok = ev.success != 0;
- *tag = cq_tag;
- if (cq_tag->FinalizeResult(tag, ok)) {
+ *tag = core_cq_tag;
+ if (core_cq_tag->FinalizeResult(tag, ok)) {
return GOT_EVENT;
}
break;
@@ -87,9 +87,9 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) {
flushed_ = true;
if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag,
&res)) {
- auto cq_tag = static_cast<internal::CompletionQueueTag*>(res_tag);
+ auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(res_tag);
*ok = res == 1;
- if (cq_tag->FinalizeResult(tag, ok)) {
+ if (core_cq_tag->FinalizeResult(tag, ok)) {
return true;
}
}
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 619aacadaa..cfaa2e7b19 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -102,6 +102,13 @@ size_t CoreCodegen::grpc_byte_buffer_length(grpc_byte_buffer* bb) {
return ::grpc_byte_buffer_length(bb);
}
+grpc_call_error CoreCodegen::grpc_call_start_batch(grpc_call* call,
+ const grpc_op* ops,
+ size_t nops, void* tag,
+ void* reserved) {
+ return ::grpc_call_start_batch(call, ops, nops, tag, reserved);
+}
+
grpc_call_error CoreCodegen::grpc_call_cancel_with_status(
grpc_call* call, grpc_status_code status, const char* description,
void* reserved) {
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index 8abd45efb7..55da89e6c8 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
#include <grpcpp/grpcpp.h>
namespace grpc {
-grpc::string Version() { return "1.17.0-dev"; }
+grpc::string Version() { return "1.18.0-dev"; }
} // namespace grpc
diff --git a/src/cpp/ext/filters/census/context.cc b/src/cpp/ext/filters/census/context.cc
index 4b3250236d..78fc69a805 100644
--- a/src/cpp/ext/filters/census/context.cc
+++ b/src/cpp/ext/filters/census/context.cc
@@ -29,9 +29,15 @@ void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
absl::string_view primary_role,
absl::string_view method, CensusContext* context) {
GrpcTraceContext trace_ctxt;
- TraceContextEncoding::Decode(tracing, &trace_ctxt);
- SpanContext parent_ctx = trace_ctxt.ToSpanContext();
- new (context) CensusContext(method, parent_ctx);
+ if (TraceContextEncoding::Decode(tracing, &trace_ctxt) !=
+ TraceContextEncoding::kEncodeDecodeFailure) {
+ SpanContext parent_ctx = trace_ctxt.ToSpanContext();
+ if (parent_ctx.IsValid()) {
+ new (context) CensusContext(method, parent_ctx);
+ return;
+ }
+ }
+ new (context) CensusContext(method);
}
void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc
index 428893f277..9ecb9de7e4 100644
--- a/src/cpp/server/channelz/channelz_service.cc
+++ b/src/cpp/server/channelz/channelz_service.cc
@@ -59,6 +59,23 @@ Status ChannelzService::GetServers(
return Status::OK;
}
+Status ChannelzService::GetServer(ServerContext* unused,
+ const channelz::v1::GetServerRequest* request,
+ channelz::v1::GetServerResponse* response) {
+ char* json_str = grpc_channelz_get_server(request->server_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::INTERNAL,
+ "grpc_channelz_get_server returned null");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
Status ChannelzService::GetServerSockets(
ServerContext* unused, const channelz::v1::GetServerSocketsRequest* request,
channelz::v1::GetServerSocketsResponse* response) {
diff --git a/src/cpp/server/channelz/channelz_service.h b/src/cpp/server/channelz/channelz_service.h
index 590b5d492e..b4a66ba1c6 100644
--- a/src/cpp/server/channelz/channelz_service.h
+++ b/src/cpp/server/channelz/channelz_service.h
@@ -36,6 +36,10 @@ class ChannelzService final : public channelz::v1::Channelz::Service {
Status GetServers(ServerContext* unused,
const channelz::v1::GetServersRequest* request,
channelz::v1::GetServersResponse* response) override;
+ // implementation of GetServer rpc
+ Status GetServer(ServerContext* unused,
+ const channelz::v1::GetServerRequest* request,
+ channelz::v1::GetServerResponse* response) override;
// implementation of GetServerSockets rpc
Status GetServerSockets(
ServerContext* unused,
diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc
index c951c69d51..44aebd2f9d 100644
--- a/src/cpp/server/health/default_health_check_service.cc
+++ b/src/cpp/server/health/default_health_check_service.cc
@@ -42,18 +42,37 @@ DefaultHealthCheckService::DefaultHealthCheckService() {
void DefaultHealthCheckService::SetServingStatus(
const grpc::string& service_name, bool serving) {
std::unique_lock<std::mutex> lock(mu_);
+ if (shutdown_) {
+ // Set to NOT_SERVING in case service_name is not in the map.
+ serving = false;
+ }
services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING);
}
void DefaultHealthCheckService::SetServingStatus(bool serving) {
const ServingStatus status = serving ? SERVING : NOT_SERVING;
std::unique_lock<std::mutex> lock(mu_);
+ if (shutdown_) {
+ return;
+ }
for (auto& p : services_map_) {
ServiceData& service_data = p.second;
service_data.SetServingStatus(status);
}
}
+void DefaultHealthCheckService::Shutdown() {
+ std::unique_lock<std::mutex> lock(mu_);
+ if (shutdown_) {
+ return;
+ }
+ shutdown_ = true;
+ for (auto& p : services_map_) {
+ ServiceData& service_data = p.second;
+ service_data.SetServingStatus(NOT_SERVING);
+ }
+}
+
DefaultHealthCheckService::ServingStatus
DefaultHealthCheckService::GetServingStatus(
const grpc::string& service_name) const {
diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h
index 450bd543f5..9551cd2e2c 100644
--- a/src/cpp/server/health/default_health_check_service.h
+++ b/src/cpp/server/health/default_health_check_service.h
@@ -237,6 +237,8 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface {
bool serving) override;
void SetServingStatus(bool serving) override;
+ void Shutdown() override;
+
ServingStatus GetServingStatus(const grpc::string& service_name) const;
HealthCheckServiceImpl* GetHealthCheckService(
@@ -272,6 +274,7 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface {
const std::shared_ptr<HealthCheckServiceImpl::CallHandler>& handler);
mutable std::mutex mu_;
+ bool shutdown_ = false; // Guarded by mu_.
std::map<grpc::string, ServiceData> services_map_; // Guarded by mu_.
std::unique_ptr<HealthCheckServiceImpl> impl_;
};
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 536bf022dd..ebb17def32 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -43,9 +43,10 @@ void AuthMetadataProcessorAyncWrapper::Process(
return;
}
if (w->processor_->IsBlocking()) {
- w->thread_pool_->Add(
- std::bind(&AuthMetadataProcessorAyncWrapper::InvokeProcessor, w,
- context, md, num_md, cb, user_data));
+ w->thread_pool_->Add([w, context, md, num_md, cb, user_data] {
+ w->AuthMetadataProcessorAyncWrapper::InvokeProcessor(context, md, num_md,
+ cb, user_data);
+ });
} else {
// invoke directly.
w->InvokeProcessor(context, md, num_md, cb, user_data);
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 8417c45e64..0dc03b6876 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -71,7 +71,9 @@ ServerBuilder::~ServerBuilder() {
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
bool is_frequently_polled) {
ServerCompletionQueue* cq = new ServerCompletionQueue(
- is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING);
+ GRPC_CQ_NEXT,
+ is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING,
+ nullptr);
cqs_.push_back(cq);
return std::unique_ptr<ServerCompletionQueue>(cq);
}
@@ -256,14 +258,22 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
// Create completion queues to listen to incoming rpc requests
for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
- sync_server_cqs->emplace_back(new ServerCompletionQueue(polling_type));
+ sync_server_cqs->emplace_back(
+ new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
}
}
- std::unique_ptr<Server> server(new Server(
- max_receive_message_size_, &args, sync_server_cqs,
- sync_server_settings_.min_pollers, sync_server_settings_.max_pollers,
- sync_server_settings_.cq_timeout_msec, resource_quota_));
+ // == Determine if the server has any callback methods ==
+ bool has_callback_methods = false;
+ for (auto it = services_.begin(); it != services_.end(); ++it) {
+ if ((*it)->service->has_callback_methods()) {
+ has_callback_methods = true;
+ break;
+ }
+ }
+
+ // TODO(vjpai): Add a section here for plugins once they can support callback
+ // methods
if (has_sync_methods) {
// This is a Sync server
@@ -275,6 +285,16 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
sync_server_settings_.cq_timeout_msec);
}
+ if (has_callback_methods) {
+ gpr_log(GPR_INFO, "Callback server.");
+ }
+
+ std::unique_ptr<Server> server(new Server(
+ max_receive_message_size_, &args, sync_server_cqs,
+ sync_server_settings_.min_pollers, sync_server_settings_.max_pollers,
+ sync_server_settings_.cq_timeout_msec, resource_quota_,
+ std::move(interceptor_creators_)));
+
ServerInitializer* initializer = server->initializer();
// Register all the completion queues with the server. i.e
@@ -288,6 +308,12 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
num_frequently_polled_cqs++;
}
+ if (has_callback_methods) {
+ auto* cq = server->CallbackCQ();
+ grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
+ num_frequently_polled_cqs++;
+ }
+
// cqs_ contains the completion queue added by calling the ServerBuilder's
// AddCompletionQueue() API. Some of them may not be frequently polled (i.e by
// calling Next() or AsyncNext()) and hence are not safe to be used for
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 7aeddff643..1e3c57446f 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -27,7 +27,9 @@
#include <grpcpp/completion_queue.h>
#include <grpcpp/generic/async_generic_service.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
+#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/method_handler_impl.h>
#include <grpcpp/impl/rpc_service_method.h>
@@ -38,8 +40,10 @@
#include <grpcpp/support/time.h>
#include "src/core/ext/transport/inproc/inproc_transport.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/completion_queue.h"
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/server/health/default_health_check_service.h"
#include "src/cpp/thread_manager/thread_manager.h"
@@ -54,6 +58,9 @@ namespace {
// max-threads set) to the server builder.
#define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX
+// How many callback requests of each method should we pre-register at start
+#define DEFAULT_CALLBACK_REQS_PER_METHOD 32
+
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
public:
~DefaultGlobalCallbacks() override {}
@@ -77,10 +84,7 @@ class ShutdownTag : public internal::CompletionQueueTag {
class DummyTag : public internal::CompletionQueueTag {
public:
- bool FinalizeResult(void** tag, bool* status) {
- *status = true;
- return true;
- }
+ bool FinalizeResult(void** tag, bool* status) { return true; }
};
class UnimplementedAsyncRequestContext {
@@ -127,10 +131,13 @@ class Server::UnimplementedAsyncResponse final
~UnimplementedAsyncResponse() { delete request_; }
bool FinalizeResult(void** tag, bool* status) override {
- internal::CallOpSet<
- internal::CallOpSendInitialMetadata,
- internal::CallOpServerSendStatus>::FinalizeResult(tag, status);
- delete this;
+ if (internal::CallOpSet<
+ internal::CallOpSendInitialMetadata,
+ internal::CallOpServerSendStatus>::FinalizeResult(tag, status)) {
+ delete this;
+ } else {
+ // The tag was swallowed due to interception. We will see it again.
+ }
return false;
}
@@ -140,9 +147,9 @@ class Server::UnimplementedAsyncResponse final
class Server::SyncRequest final : public internal::CompletionQueueTag {
public:
- SyncRequest(internal::RpcServiceMethod* method, void* tag)
+ SyncRequest(internal::RpcServiceMethod* method, void* method_tag)
: method_(method),
- tag_(tag),
+ method_tag_(method_tag),
in_flight_(false),
has_request_payload_(
method->method_type() == internal::RpcMethod::NORMAL_RPC ||
@@ -169,10 +176,10 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
GPR_ASSERT(cq_ && !in_flight_);
in_flight_ = true;
- if (tag_) {
+ if (method_tag_) {
if (GRPC_CALL_OK !=
grpc_server_request_registered_call(
- server, tag_, &call_, &deadline_, &request_metadata_,
+ server, method_tag_, &call_, &deadline_, &request_metadata_,
has_request_payload_ ? &request_payload_ : nullptr, cq_,
notify_cq, this)) {
TeardownRequest();
@@ -192,9 +199,21 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
}
}
+ void PostShutdownCleanup() {
+ if (call_) {
+ grpc_call_unref(call_);
+ call_ = nullptr;
+ }
+ if (cq_) {
+ grpc_completion_queue_destroy(cq_);
+ cq_ = nullptr;
+ }
+ }
+
bool FinalizeResult(void** tag, bool* status) override {
if (!*status) {
grpc_completion_queue_destroy(cq_);
+ cq_ = nullptr;
}
if (call_details_) {
deadline_ = call_details_->deadline;
@@ -204,17 +223,26 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
return true;
}
+ // The CallData class represents a call that is "active" as opposed
+ // to just being requested. It wraps and takes ownership of the cq from
+ // the call request
class CallData final {
public:
explicit CallData(Server* server, SyncRequest* mrd)
: cq_(mrd->cq_),
- call_(mrd->call_, server, &cq_, server->max_receive_message_size()),
ctx_(mrd->deadline_, &mrd->request_metadata_),
has_request_payload_(mrd->has_request_payload_),
request_payload_(has_request_payload_ ? mrd->request_payload_
: nullptr),
+ request_(nullptr),
method_(mrd->method_),
- server_(server) {
+ call_(
+ mrd->call_, server, &cq_, server->max_receive_message_size(),
+ ctx_.set_server_rpc_info(method_->name(), method_->method_type(),
+ server->interceptor_creators_)),
+ server_(server),
+ global_callbacks_(nullptr),
+ resources_(false) {
ctx_.set_call(mrd->call_);
ctx_.cq_ = &cq_;
GPR_ASSERT(mrd->in_flight_);
@@ -230,38 +258,79 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
bool resources) {
- ctx_.BeginCompletionOp(&call_);
- global_callbacks->PreSynchronousRequest(&ctx_);
- auto* handler = resources ? method_->handler()
- : server_->resource_exhausted_handler_.get();
- handler->RunHandler(internal::MethodHandler::HandlerParameter(
- &call_, &ctx_, request_payload_));
- global_callbacks->PostSynchronousRequest(&ctx_);
- request_payload_ = nullptr;
-
- cq_.Shutdown();
+ global_callbacks_ = global_callbacks;
+ resources_ = resources;
+
+ interceptor_methods_.SetCall(&call_);
+ interceptor_methods_.SetReverse();
+ // Set interception point for RECV INITIAL METADATA
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ interceptor_methods_.SetRecvInitialMetadata(&ctx_.client_metadata_);
+
+ if (has_request_payload_) {
+ // Set interception point for RECV MESSAGE
+ auto* handler = resources_ ? method_->handler()
+ : server_->resource_exhausted_handler_.get();
+ request_ = handler->Deserialize(call_.call(), request_payload_,
+ &request_status_);
+
+ request_payload_ = nullptr;
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ interceptor_methods_.SetRecvMessage(request_);
+ }
- internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
- cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+ if (interceptor_methods_.RunInterceptors(
+ [this]() { ContinueRunAfterInterception(); })) {
+ ContinueRunAfterInterception();
+ } else {
+ // There were interceptors to be run, so ContinueRunAfterInterception
+ // will be run when interceptors are done.
+ }
+ }
- /* Ensure the cq_ is shutdown */
- DummyTag ignored_tag;
- GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
+ void ContinueRunAfterInterception() {
+ {
+ ctx_.BeginCompletionOp(&call_, nullptr, nullptr);
+ global_callbacks_->PreSynchronousRequest(&ctx_);
+ auto* handler = resources_ ? method_->handler()
+ : server_->resource_exhausted_handler_.get();
+ handler->RunHandler(internal::MethodHandler::HandlerParameter(
+ &call_, &ctx_, request_, request_status_, nullptr));
+ request_ = nullptr;
+ global_callbacks_->PostSynchronousRequest(&ctx_);
+
+ cq_.Shutdown();
+
+ internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
+ cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+ /* Ensure the cq_ is shutdown */
+ DummyTag ignored_tag;
+ GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
+ }
+ delete this;
}
private:
CompletionQueue cq_;
- internal::Call call_;
ServerContext ctx_;
const bool has_request_payload_;
grpc_byte_buffer* request_payload_;
+ void* request_;
+ Status request_status_;
internal::RpcServiceMethod* const method_;
+ internal::Call call_;
Server* server_;
+ std::shared_ptr<GlobalCallbacks> global_callbacks_;
+ bool resources_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
private:
internal::RpcServiceMethod* const method_;
- void* const tag_;
+ void* const method_tag_;
bool in_flight_;
const bool has_request_payload_;
grpc_call* call_;
@@ -272,6 +341,176 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
grpc_completion_queue* cq_;
};
+class Server::CallbackRequest final : public internal::CompletionQueueTag {
+ public:
+ CallbackRequest(Server* server, internal::RpcServiceMethod* method,
+ void* method_tag)
+ : server_(server),
+ method_(method),
+ method_tag_(method_tag),
+ has_request_payload_(
+ method->method_type() == internal::RpcMethod::NORMAL_RPC ||
+ method->method_type() == internal::RpcMethod::SERVER_STREAMING),
+ cq_(server->CallbackCQ()),
+ tag_(this) {
+ Setup();
+ }
+
+ ~CallbackRequest() { Clear(); }
+
+ void Request() {
+ if (method_tag_) {
+ if (GRPC_CALL_OK !=
+ grpc_server_request_registered_call(
+ server_->c_server(), method_tag_, &call_, &deadline_,
+ &request_metadata_,
+ has_request_payload_ ? &request_payload_ : nullptr, cq_->cq(),
+ cq_->cq(), static_cast<void*>(&tag_))) {
+ return;
+ }
+ } else {
+ if (!call_details_) {
+ call_details_ = new grpc_call_details;
+ grpc_call_details_init(call_details_);
+ }
+ if (grpc_server_request_call(server_->c_server(), &call_, call_details_,
+ &request_metadata_, cq_->cq(), cq_->cq(),
+ static_cast<void*>(&tag_)) != GRPC_CALL_OK) {
+ return;
+ }
+ }
+ }
+
+ bool FinalizeResult(void** tag, bool* status) override { return false; }
+
+ private:
+ class CallbackCallTag : public grpc_experimental_completion_queue_functor {
+ public:
+ CallbackCallTag(Server::CallbackRequest* req) : req_(req) {
+ functor_run = &CallbackCallTag::StaticRun;
+ }
+
+ // force_run can not be performed on a tag if operations using this tag
+ // have been sent to PerformOpsOnCall. It is intended for error conditions
+ // that are detected before the operations are internally processed.
+ void force_run(bool ok) { Run(ok); }
+
+ private:
+ Server::CallbackRequest* req_;
+ internal::Call* call_;
+
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ static_cast<CallbackCallTag*>(cb)->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
+ void* ignored = req_;
+ bool new_ok = ok;
+ GPR_ASSERT(!req_->FinalizeResult(&ignored, &new_ok));
+ GPR_ASSERT(ignored == req_);
+
+ if (!ok) {
+ // The call has been shutdown
+ req_->Clear();
+ return;
+ }
+
+ // Bind the call, deadline, and metadata from what we got
+ req_->ctx_.set_call(req_->call_);
+ req_->ctx_.cq_ = req_->cq_;
+ req_->ctx_.BindDeadlineAndMetadata(req_->deadline_,
+ &req_->request_metadata_);
+ req_->request_metadata_.count = 0;
+
+ // Create a C++ Call to control the underlying core call
+ call_ = new (grpc_call_arena_alloc(req_->call_, sizeof(internal::Call)))
+ internal::Call(
+ req_->call_, req_->server_, req_->cq_,
+ req_->server_->max_receive_message_size(),
+ req_->ctx_.set_server_rpc_info(
+ req_->method_->name(), req_->method_->method_type(),
+ req_->server_->interceptor_creators_));
+
+ req_->interceptor_methods_.SetCall(call_);
+ req_->interceptor_methods_.SetReverse();
+ // Set interception point for RECV INITIAL METADATA
+ req_->interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ req_->interceptor_methods_.SetRecvInitialMetadata(
+ &req_->ctx_.client_metadata_);
+
+ if (req_->has_request_payload_) {
+ // Set interception point for RECV MESSAGE
+ req_->request_ = req_->method_->handler()->Deserialize(
+ req_->call_, req_->request_payload_, &req_->request_status_);
+ req_->request_payload_ = nullptr;
+ req_->interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ req_->interceptor_methods_.SetRecvMessage(req_->request_);
+ }
+
+ if (req_->interceptor_methods_.RunInterceptors(
+ [this] { ContinueRunAfterInterception(); })) {
+ ContinueRunAfterInterception();
+ } else {
+ // There were interceptors to be run, so ContinueRunAfterInterception
+ // will be run when interceptors are done.
+ }
+ }
+ void ContinueRunAfterInterception() {
+ req_->method_->handler()->RunHandler(
+ internal::MethodHandler::HandlerParameter(
+ call_, &req_->ctx_, req_->request_, req_->request_status_,
+ [this] {
+ req_->Reset();
+ req_->Request();
+ }));
+ }
+ };
+
+ void Reset() {
+ Clear();
+ Setup();
+ }
+
+ void Clear() {
+ if (call_details_) {
+ delete call_details_;
+ call_details_ = nullptr;
+ }
+ grpc_metadata_array_destroy(&request_metadata_);
+ if (has_request_payload_ && request_payload_) {
+ grpc_byte_buffer_destroy(request_payload_);
+ }
+ ctx_.Clear();
+ interceptor_methods_.ClearState();
+ }
+
+ void Setup() {
+ grpc_metadata_array_init(&request_metadata_);
+ ctx_.Setup(gpr_inf_future(GPR_CLOCK_REALTIME));
+ request_payload_ = nullptr;
+ request_ = nullptr;
+ request_status_ = Status();
+ }
+
+ Server* const server_;
+ internal::RpcServiceMethod* const method_;
+ void* const method_tag_;
+ const bool has_request_payload_;
+ grpc_byte_buffer* request_payload_;
+ void* request_;
+ Status request_status_;
+ grpc_call_details* call_details_ = nullptr;
+ grpc_call* call_;
+ gpr_timespec deadline_;
+ grpc_metadata_array request_metadata_;
+ CompletionQueue* cq_;
+ CallbackCallTag tag_;
+ ServerContext ctx_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
+};
+
// Implementation of ThreadManager. Each instance of SyncRequestThreadManager
// manages a pool of threads that poll for incoming Sync RPCs and call the
// appropriate RPC handlers
@@ -318,8 +557,9 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
if (ok) {
- // Calldata takes ownership of the completion queue inside sync_req
- SyncRequest::CallData cd(server_, sync_req);
+ // Calldata takes ownership of the completion queue and interceptors
+ // inside sync_req
+ auto* cd = new SyncRequest::CallData(server_, sync_req);
// Prepare for the next request
if (!IsShutdown()) {
sync_req->SetupRequest(); // Create new completion queue for sync_req
@@ -327,7 +567,7 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
GPR_TIMER_SCOPE("cd.Run()", 0);
- cd.Run(global_callbacks_, resources);
+ cd->Run(global_callbacks_, resources);
}
// TODO (sreek) If ok is false here (which it isn't in case of
// grpc_request_registered_call), we should still re-queue the request
@@ -359,7 +599,17 @@ class Server::SyncRequestThreadManager : public ThreadManager {
void* tag;
bool ok;
while (server_cq_->Next(&tag, &ok)) {
- // Do nothing
+ if (ok) {
+ // If a request was pulled off the queue, it means that the thread
+ // handling the request added it to the completion queue after shutdown
+ // was called - because the thread had already started and checked the
+ // shutdown flag before shutdown was called. In this case, we simply
+ // clean it up here, *after* calling wait on all the worker threads, at
+ // which point we are certain no in-flight requests will add more to the
+ // queue. This fixes an intermittent memory leak on shutdown.
+ SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
+ sync_req->PostShutdownCleanup();
+ }
}
}
@@ -389,8 +639,12 @@ Server::Server(
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
- grpc_resource_quota* server_rq)
- : max_receive_message_size_(max_receive_message_size),
+ grpc_resource_quota* server_rq,
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators)
+ : interceptor_creators_(std::move(interceptor_creators)),
+ max_receive_message_size_(max_receive_message_size),
sync_server_cqs_(std::move(sync_server_cqs)),
started_(false),
shutdown_(false),
@@ -446,6 +700,9 @@ Server::Server(
Server::~Server() {
{
std::unique_lock<std::mutex> lock(mu_);
+ if (callback_cq_ != nullptr) {
+ callback_cq_->Shutdown();
+ }
if (started_ && !shutdown_) {
lock.unlock();
Shutdown();
@@ -473,14 +730,15 @@ std::shared_ptr<Channel> Server::InProcessChannel(
grpc_channel_args channel_args = args.c_channel_args();
return CreateChannelInternal(
"inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr),
- nullptr);
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
}
std::shared_ptr<Channel>
Server::experimental_type::InProcessChannelWithInterceptors(
const ChannelArguments& args,
- std::unique_ptr<std::vector<
- std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
grpc_channel_args channel_args = args.c_channel_args();
return CreateChannelInternal(
@@ -518,21 +776,31 @@ bool Server::RegisterService(const grpc::string* host, Service* service) {
}
internal::RpcServiceMethod* method = it->get();
- void* tag = grpc_server_register_method(
+ void* method_registration_tag = grpc_server_register_method(
server_, method->name(), host ? host->c_str() : nullptr,
PayloadHandlingForMethod(method), 0);
- if (tag == nullptr) {
+ if (method_registration_tag == nullptr) {
gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
method->name());
return false;
}
- if (method->handler() == nullptr) { // Async method
- method->set_server_tag(tag);
- } else {
+ if (method->handler() == nullptr) { // Async method without handler
+ method->set_server_tag(method_registration_tag);
+ } else if (method->api_type() ==
+ internal::RpcServiceMethod::ApiType::SYNC) {
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
- (*it)->AddSyncMethod(method, tag);
+ (*it)->AddSyncMethod(method, method_registration_tag);
+ }
+ } else {
+ // a callback method. Register at least some callback requests
+ // TODO(vjpai): Register these dynamically based on need
+ for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) {
+ auto* req = new CallbackRequest(this, method, method_registration_tag);
+ callback_reqs_.emplace_back(req);
}
+ // Enqueue it so that it will be Request'ed later once
+ // all request matchers are created at core server startup
}
method_name = method->name();
@@ -583,7 +851,8 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
// performance. This ensures that we don't introduce thread hops
// for application requests that wind up on this CQ, which is polled
// in its own thread.
- health_check_cq = new ServerCompletionQueue(GRPC_CQ_NON_POLLING);
+ health_check_cq =
+ new ServerCompletionQueue(GRPC_CQ_NEXT, GRPC_CQ_NON_POLLING, nullptr);
grpc_server_register_completion_queue(server_, health_check_cq->cq(),
nullptr);
default_health_check_service_impl =
@@ -620,6 +889,10 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
(*it)->Start();
}
+ for (auto& cbreq : callback_reqs_) {
+ cbreq->Request();
+ }
+
if (default_health_check_service_impl != nullptr) {
default_health_check_service_impl->StartServingThread();
}
@@ -681,31 +954,27 @@ void Server::Wait() {
void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) {
- static const size_t MAX_OPS = 8;
- size_t nops = 0;
- grpc_op cops[MAX_OPS];
- ops->FillOps(call->call(), cops, &nops);
- auto result =
- grpc_call_start_batch(call->call(), cops, nops, ops->cq_tag(), nullptr);
- if (result != GRPC_CALL_OK) {
- gpr_log(GPR_ERROR, "Fatal: grpc_call_start_batch returned %d", result);
- grpc_call_log_batch(__FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR,
- call->call(), cops, nops, ops);
- abort();
- }
+ ops->FillOps(call);
}
ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
- void* tag, bool delete_on_finalize)
+ ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
: server_(server),
context_(context),
stream_(stream),
call_cq_(call_cq),
+ notification_cq_(notification_cq),
tag_(tag),
delete_on_finalize_(delete_on_finalize),
- call_(nullptr) {
+ call_(nullptr),
+ done_intercepting_(false) {
+ /* Set up interception state partially for the receive ops. call_wrapper_ is
+ * not filled at this point, but it will be filled before the interceptors are
+ * run. */
+ interceptor_methods_.SetCall(&call_wrapper_);
+ interceptor_methods_.SetReverse();
call_cq_->RegisterAvalanching(); // This op will trigger more ops
}
@@ -715,15 +984,43 @@ ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() {
bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
bool* status) {
+ if (done_intercepting_) {
+ *tag = tag_;
+ if (delete_on_finalize_) {
+ delete this;
+ }
+ return true;
+ }
context_->set_call(call_);
context_->cq_ = call_cq_;
- internal::Call call(call_, server_, call_cq_,
- server_->max_receive_message_size());
- if (*status && call_) {
- context_->BeginCompletionOp(&call);
+ if (call_wrapper_.call() == nullptr) {
+ // Fill it since it is empty.
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(), nullptr);
}
+
// just the pointers inside call are copied here
- stream_->BindCall(&call);
+ stream_->BindCall(&call_wrapper_);
+
+ if (*status && call_ && call_wrapper_.server_rpc_info()) {
+ done_intercepting_ = true;
+ // Set interception point for RECV INITIAL METADATA
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_);
+ if (interceptor_methods_.RunInterceptors(
+ [this]() { ContinueFinalizeResultAfterInterception(); })) {
+ // There are no interceptors to run. Continue
+ } else {
+ // There were interceptors to be run, so
+ // ContinueFinalizeResultAfterInterception will be run when interceptors
+ // are done.
+ return false;
+ }
+ }
+ if (*status && call_) {
+ context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr);
+ }
*tag = tag_;
if (delete_on_finalize_) {
delete this;
@@ -731,11 +1028,27 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
return true;
}
+void ServerInterface::BaseAsyncRequest::
+ ContinueFinalizeResultAfterInterception() {
+ context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr);
+ // Queue a tag which will be returned immediately
+ grpc_core::ExecCtx exec_ctx;
+ grpc_cq_begin_op(notification_cq_->cq(), this);
+ grpc_cq_end_op(
+ notification_cq_->cq(), this, GRPC_ERROR_NONE,
+ [](void* arg, grpc_cq_completion* completion) { delete completion; },
+ nullptr, new grpc_cq_completion());
+}
+
ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest(
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
- void* tag)
- : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {}
+ ServerCompletionQueue* notification_cq, void* tag, const char* name,
+ internal::RpcMethod::RpcType type)
+ : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
+ true),
+ name_(name),
+ type_(type) {}
void ServerInterface::RegisteredAsyncRequest::IssueRequest(
void* registered_method, grpc_byte_buffer** payload,
@@ -751,7 +1064,7 @@ ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
ServerInterface* server, GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
- : BaseAsyncRequest(server, context, stream, call_cq, tag,
+ : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
delete_on_finalize) {
grpc_call_details_init(&call_details_);
GPR_ASSERT(notification_cq);
@@ -764,6 +1077,10 @@ ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
bool* status) {
+ // If we are done intercepting, there is nothing more for us to do
+ if (done_intercepting_) {
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
// TODO(yangg) remove the copy here.
if (*status) {
static_cast<GenericServerContext*>(context_)->method_ =
@@ -774,16 +1091,27 @@ bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
}
grpc_slice_unref(call_details_.method);
grpc_slice_unref(call_details_.host);
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(),
+ context_->set_server_rpc_info(
+ static_cast<GenericServerContext*>(context_)->method_.c_str(),
+ internal::RpcMethod::BIDI_STREAMING,
+ *server_->interceptor_creators()));
return BaseAsyncRequest::FinalizeResult(tag, status);
}
bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag,
bool* status) {
- if (GenericAsyncRequest::FinalizeResult(tag, status) && *status) {
- new UnimplementedAsyncRequest(server_, cq_);
- new UnimplementedAsyncResponse(this);
+ if (GenericAsyncRequest::FinalizeResult(tag, status)) {
+ // We either had no interceptors run or we are done intercepting
+ if (*status) {
+ new UnimplementedAsyncRequest(server_, cq_);
+ new UnimplementedAsyncResponse(this);
+ } else {
+ delete this;
+ }
} else {
- delete this;
+ // The tag was swallowed due to interception. We will see it again.
}
return false;
}
@@ -798,4 +1126,41 @@ Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse(
ServerInitializer* Server::initializer() { return server_initializer_.get(); }
+namespace {
+class ShutdownCallback : public grpc_experimental_completion_queue_functor {
+ public:
+ ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
+ // TakeCQ takes ownership of the cq into the shutdown callback
+ // so that the shutdown callback will be responsible for destroying it
+ void TakeCQ(CompletionQueue* cq) { cq_ = cq; }
+
+ // The Run function will get invoked by the completion queue library
+ // when the shutdown is actually complete
+ static void Run(grpc_experimental_completion_queue_functor* cb, int) {
+ auto* callback = static_cast<ShutdownCallback*>(cb);
+ delete callback->cq_;
+ delete callback;
+ }
+
+ private:
+ CompletionQueue* cq_ = nullptr;
+};
+} // namespace
+
+CompletionQueue* Server::CallbackCQ() {
+ // TODO(vjpai): Consider using a single global CQ for the default CQ
+ // if there is no explicit per-server CQ registered
+ std::lock_guard<std::mutex> l(mu_);
+ if (callback_cq_ == nullptr) {
+ auto* shutdown_callback = new ShutdownCallback;
+ callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
+ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
+ shutdown_callback});
+
+ // Transfer ownership of the new cq to its own shutdown callback
+ shutdown_callback->TakeCQ(callback_cq_);
+ }
+ return callback_cq_;
+};
+
} // namespace grpc
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index bd532a968d..1b524bc3e8 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -17,6 +17,7 @@
*/
#include <grpcpp/server_context.h>
+#include <grpcpp/support/server_callback.h>
#include <algorithm>
#include <mutex>
@@ -41,13 +42,30 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
public:
// initial refs: one in the server context, one in the cq
// must ref the call before calling constructor and after deleting this
- CompletionOp(grpc_call* call)
- : call_(call),
+ CompletionOp(internal::Call* call, internal::ServerReactor* reactor)
+ : call_(*call),
+ reactor_(reactor),
has_tag_(false),
tag_(nullptr),
+ core_cq_tag_(this),
refs_(2),
finalized_(false),
- cancelled_(0) {}
+ cancelled_(0),
+ done_intercepting_(false) {}
+
+ // CompletionOp isn't copyable or movable
+ CompletionOp(const CompletionOp&) = delete;
+ CompletionOp& operator=(const CompletionOp&) = delete;
+ CompletionOp(CompletionOp&&) = delete;
+ CompletionOp& operator=(CompletionOp&&) = delete;
+
+ ~CompletionOp() {
+ if (call_.server_rpc_info()) {
+ call_.server_rpc_info()->Unref();
+ }
+ }
+
+ void FillOps(internal::Call* call) override;
// This should always be arena allocated in the call, so override delete.
// But this class is not trivially destructible, so must actually call delete
@@ -63,7 +81,6 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { assert(0); }
- void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override;
bool FinalizeResult(void** tag, bool* status) override;
bool CheckCancelled(CompletionQueue* cq) {
@@ -77,107 +94,207 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
tag_ = tag;
}
- /// TODO(vjpai): Allow override of cq_tag if appropriate for callback API
- void* cq_tag() override { return this; }
+ void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; }
+
+ void* core_cq_tag() override { return core_cq_tag_; }
void Unref();
+ // This will be called while interceptors are run if the RPC is a hijacked
+ // RPC. This should set hijacking state for each of the ops.
+ void SetHijackingState() override {
+ /* Servers don't allow hijacking */
+ GPR_CODEGEN_ASSERT(false);
+ }
+
+ /* Should be called after interceptors are done running */
+ void ContinueFillOpsAfterInterception() override {}
+
+ /* Should be called after interceptors are done running on the finalize result
+ * path */
+ void ContinueFinalizeResultAfterInterception() override {
+ done_intercepting_ = true;
+ if (!has_tag_) {
+ /* We don't have a tag to return. */
+ std::unique_lock<std::mutex> lock(mu_);
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return;
+ }
+ /* Start a dummy op so that we can return the tag */
+ GPR_CODEGEN_ASSERT(
+ GRPC_CALL_OK ==
+ grpc_call_start_batch(call_.call(), nullptr, 0, core_cq_tag_, nullptr));
+ }
+
private:
bool CheckCancelledNoPluck() {
std::lock_guard<std::mutex> g(mu_);
return finalized_ ? (cancelled_ != 0) : false;
}
- grpc_call* call_;
+ internal::Call call_;
+ internal::ServerReactor* reactor_;
bool has_tag_;
void* tag_;
+ void* core_cq_tag_;
std::mutex mu_;
int refs_;
bool finalized_;
- int cancelled_;
+ int cancelled_; // This is an int (not bool) because it is passed to core
+ bool done_intercepting_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
void ServerContext::CompletionOp::Unref() {
std::unique_lock<std::mutex> lock(mu_);
if (--refs_ == 0) {
lock.unlock();
- // Save aside the call pointer before deleting for later unref
- grpc_call* call = call_;
+ grpc_call* call = call_.call();
delete this;
grpc_call_unref(call);
}
}
-void ServerContext::CompletionOp::FillOps(grpc_call* call, 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 = nullptr;
- *nops = 1;
+void ServerContext::CompletionOp::FillOps(internal::Call* call) {
+ grpc_op ops;
+ ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ ops.data.recv_close_on_server.cancelled = &cancelled_;
+ ops.flags = 0;
+ ops.reserved = nullptr;
+ interceptor_methods_.SetCall(&call_);
+ interceptor_methods_.SetReverse();
+ interceptor_methods_.SetCallOpSetInterface(this);
+ GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), &ops, 1,
+ core_cq_tag_, nullptr));
+ /* No interceptors to run here */
}
bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
+ bool ret = false;
std::unique_lock<std::mutex> lock(mu_);
+ if (done_intercepting_) {
+ /* We are done intercepting. */
+ if (has_tag_) {
+ *tag = tag_;
+ ret = true;
+ }
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return ret;
+ }
finalized_ = true;
- bool ret = false;
- if (has_tag_) {
- *tag = tag_;
- ret = true;
+
+ // If for some reason the incoming status is false, mark that as a
+ // cancellation.
+ // TODO(vjpai): does this ever happen?
+ if (!*status) {
+ cancelled_ = 1;
}
- if (!*status) cancelled_ = 1;
- if (--refs_ == 0) {
- lock.unlock();
- // Save aside the call pointer before deleting for later unref
- grpc_call* call = call_;
- delete this;
- grpc_call_unref(call);
+
+ if (cancelled_ && (reactor_ != nullptr)) {
+ reactor_->OnCancel();
}
- return ret;
+ /* Release the lock since we are going to be running through interceptors now
+ */
+ lock.unlock();
+ /* Add interception point and run through interceptors */
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_CLOSE);
+ if (interceptor_methods_.RunInterceptors()) {
+ /* No interceptors were run */
+ if (has_tag_) {
+ *tag = tag_;
+ ret = true;
+ }
+ lock.lock();
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return ret;
+ }
+ /* There are interceptors to be run. Return false for now */
+ return false;
}
// ServerContext body
-ServerContext::ServerContext()
- : completion_op_(nullptr),
- has_notify_when_done_tag_(false),
- async_notify_when_done_tag_(nullptr),
- deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
- call_(nullptr),
- cq_(nullptr),
- sent_initial_metadata_(false),
- compression_level_set_(false),
- has_pending_ops_(false) {}
-
-ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata_array* arr)
- : completion_op_(nullptr),
- has_notify_when_done_tag_(false),
- async_notify_when_done_tag_(nullptr),
- deadline_(deadline),
- call_(nullptr),
- cq_(nullptr),
- sent_initial_metadata_(false),
- compression_level_set_(false),
- has_pending_ops_(false) {
+ServerContext::ServerContext() { Setup(gpr_inf_future(GPR_CLOCK_REALTIME)); }
+
+ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata_array* arr) {
+ Setup(deadline);
std::swap(*client_metadata_.arr(), *arr);
}
-ServerContext::~ServerContext() {
- if (call_) {
- grpc_call_unref(call_);
- }
+void ServerContext::Setup(gpr_timespec deadline) {
+ completion_op_ = nullptr;
+ has_notify_when_done_tag_ = false;
+ async_notify_when_done_tag_ = nullptr;
+ deadline_ = deadline;
+ call_ = nullptr;
+ cq_ = nullptr;
+ sent_initial_metadata_ = false;
+ compression_level_set_ = false;
+ has_pending_ops_ = false;
+ rpc_info_ = nullptr;
+}
+
+void ServerContext::BindDeadlineAndMetadata(gpr_timespec deadline,
+ grpc_metadata_array* arr) {
+ deadline_ = deadline;
+ std::swap(*client_metadata_.arr(), *arr);
+}
+
+ServerContext::~ServerContext() { Clear(); }
+
+void ServerContext::Clear() {
+ auth_context_.reset();
+ initial_metadata_.clear();
+ trailing_metadata_.clear();
+ client_metadata_.Reset();
if (completion_op_) {
completion_op_->Unref();
+ completion_op_ = nullptr;
+ completion_tag_.Clear();
+ }
+ if (rpc_info_) {
+ rpc_info_->Unref();
+ rpc_info_ = nullptr;
+ }
+ if (call_) {
+ auto* call = call_;
+ call_ = nullptr;
+ grpc_call_unref(call);
}
}
-void ServerContext::BeginCompletionOp(internal::Call* call) {
+void ServerContext::BeginCompletionOp(internal::Call* call,
+ std::function<void(bool)> callback,
+ internal::ServerReactor* reactor) {
GPR_ASSERT(!completion_op_);
+ if (rpc_info_) {
+ rpc_info_->Ref();
+ }
grpc_call_ref(call->call());
completion_op_ =
new (grpc_call_arena_alloc(call->call(), sizeof(CompletionOp)))
- CompletionOp(call->call());
- if (has_notify_when_done_tag_) {
+ CompletionOp(call, reactor);
+ if (callback != nullptr) {
+ completion_tag_.Set(call->call(), std::move(callback), completion_op_);
+ completion_op_->set_core_cq_tag(&completion_tag_);
+ completion_op_->set_tag(completion_op_);
+ } else if (has_notify_when_done_tag_) {
completion_op_->set_tag(async_notify_when_done_tag_);
}
call->PerformOps(completion_op_);
@@ -198,6 +315,12 @@ void ServerContext::AddTrailingMetadata(const grpc::string& key,
}
void ServerContext::TryCancel() const {
+ internal::CancelInterceptorBatchMethods cancel_methods;
+ if (rpc_info_) {
+ for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) {
+ rpc_info_->RunInterceptor(&cancel_methods, i);
+ }
+ }
grpc_call_error err = grpc_call_cancel_with_status(
call_, GRPC_STATUS_CANCELLED, "Cancelled on the server side", nullptr);
if (err != GRPC_CALL_OK) {
@@ -206,12 +329,15 @@ void ServerContext::TryCancel() const {
}
bool ServerContext::IsCancelled() const {
- if (has_notify_when_done_tag_) {
- // when using async API, but the result is only valid
+ if (completion_tag_) {
+ // When using callback API, this result is always valid.
+ return completion_op_->CheckCancelledAsync();
+ } else if (has_notify_when_done_tag_) {
+ // When using async API, the result is only valid
// if the tag has already been delivered at the completion queue
return completion_op_ && completion_op_->CheckCancelledAsync();
} else {
- // when using sync API
+ // when using sync API, the result is always valid
return completion_op_ && completion_op_->CheckCancelled(cq_);
}
}
diff --git a/src/csharp/BUILD-INTEGRATION.md b/src/csharp/BUILD-INTEGRATION.md
new file mode 100644
index 0000000000..3addc2403c
--- /dev/null
+++ b/src/csharp/BUILD-INTEGRATION.md
@@ -0,0 +1,357 @@
+Protocol Buffers/gRPC Integration Into .NET Build
+=================================================
+
+With Grpc.Tools package version 1.17 we made it easier to compile .proto files
+in your project using the `dotnet build` command, Visual Studio, or command-line
+MSBuild. You need to configure the .csproj project according to the way you want
+to integrate Protocol Buffer files into your build. If you are upgrading an
+existing project, read through this list of common scenarios and decide if any
+one of them matches your approach. The protoc command line migration is
+explained near the end of this document; this migration may be the quickest but
+not the long-term solution.
+
+There is also a Reference section at the end of the file.
+
+Reporting issues
+----------------
+
+First thing first, if you found a bug in this new build system, or have a
+scenario that is not easily covered, please open an [issue in the gRPC
+repository](https://github.com/grpc/grpc/issues), and **tag the user @kkm000**
+somewhere in the text (for example, include `/cc @kkm000` at end of the issue
+text) to seize his immediate attention.
+
+Common scenarios
+----------------
+
+### I just want to compile .proto files into my library
+
+This is the approach taken by the examples in the `csharp/examples` directory.
+Protoc output files (for example, `Helloworld.cs` and `HelloworldGrpc.cs`
+compiled from `helloworld.proto`) are placed among *object* and other temporary
+files of your project, and automatically provided as inputs to the C# compiler.
+As with other automatically generated .cs files, they are included in the source
+and symbols NuGet package, if you build one.
+
+Simply reference your .proto files in a `<Protobuf>` item group. The following
+example will add all .proto files in a project and all its subdirectories
+(excluding special directories such as `bin` and `obj`):
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="**/*.proto" />
+ </ItemGroup>
+```
+
+You must add a reference to the NuGet packages Grpc.Tools and Grpc (the latter
+is a meta-package, in turn referencing Grpc.Core and Google.Protobuf packages).
+It is **very important** to mark Grpc.Tools as a development-only dependency, so
+that the *users* of your library do not fetch the tools package:
+
+* "Classic" .csproj with `packages.config` (Visual Studio, Mono): This is
+ handled automatically by NuGet. See the attribute added by Visual Studio to the
+ [packages.config](../../examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config#L6)
+ file in the HelloworldLegacyCsproj/Greeter example.
+
+* "SDK" .csproj (Visual Studio, `dotnet new`): Add an attribute
+ `PrivateAssets="All"` to the Grpc.Tools package reference. See an example in the
+ [Greeter.csproj](../../examples/csharp/Helloworld/Greeter/Greeter.csproj#L10)
+ example project in this repository. If adding a package reference in Visual
+ Studio, edit the project file and add this attribute. [This is a bug in NuGet
+ client](https://github.com/NuGet/Home/issues/4125).
+
+If building a NuGet package from your library with the nuget command line tool
+from a .nuspec file, then the spec file may (and probably should) reference the
+Grpc metapackage, but **do not add a reference to Grpc.Tools** to it. .NET "SDK"
+projects handle this automatically when called from `dotnet pack` by excluding
+any packages with private assets, such as thus marked Grpc.Tools.
+
+#### Per-file options that can be set in Visual Studio
+
+For a "classic" project, you can only add .proto files with all options set to
+default (if you find it necessary to modify these options, then hand-edit the
+.csproj file). Click on the "show all files" button, add files to project, then
+change file type of the .proto files to "Protobuf" in the Properties window
+drop-down. This menu item will appear after you import the Grpc.Tools package:
+
+![Properties in a classic project](doc/integration.md-fig.1-classic.png)
+
+For an "SDK" project, you have more control of some frequently used options.
+**You may need to open and close Visual Studio** for this form to appear in the
+properties window after adding a reference to Grpc.Tools package (we do not know
+whether this is a bug or by design, but it looks like a bug):
+
+![Properties in an SDK project](doc/integration.md-fig.2-sdk.png)
+
+You can also change options of multiple files at once by selecting them in the
+Project Explorer together.
+
+See the Reference section at end of this file for options that can be set
+per-file by modifying the source .csproj directly.
+
+#### My .proto files are in a directory outside the project
+
+Refer to the example files
+[RouteGuide.csproj](../../examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj#L58-L60)
+and [Greeter.csproj](../../examples/csharp/Helloworld/Greeter/Greeter.csproj#L11)
+in this repository. For the files to show up in Visual Studio properly, add a
+`Link` attribute with just a filename to the `<Protobuf>` item. This will be the
+display name of the file. In the `Include` attribute, specify the complete path
+to file. A relative path is based off the project directory.
+
+Or, if using Visual Studio, add files _as links_ from outside directory. In the
+Add Files dialog, there is a little [down arrow near the Open
+button](https://stackoverflow.com/a/9770061). Click on it, and choose "Add as
+link". If you do not select this option, Visual Studio will copy files to the
+project directory instead.
+
+### I just want to generate proto and gRPC C# sources from my .proto files (no C# compile)
+
+Suppose you want to place generated files right beside each respective source
+.proto file. Create a .csproj library file in the common root of your .proto
+tree, and add a reference to Grpc.Tools package (this works in Windows too, `$`
+below stands for a command prompt in either platform):
+
+```
+/myproject/myprotofiles$ dotnet new classlib
+ . . .
+ Restoring packages for /myproject/myprotofiles/myprotofiles.csproj...
+ . . .
+/myproject/myprotofiles$ rm *.cs <-- remove all *.cs files from template;
+C:\myproject\myprotofiles> del *.cs /y <-- on Windows, use the del command instead.
+/myproject/myprotofiles$ dotnet add package Grpc.Tools
+```
+
+(the latter command also accepts an optional `--version X.Y` switch for a
+specific version of package, should you need one). Next open the generated
+.csproj file in a text editor.
+
+Since you are not building a package, you may not worry about adding
+`PrivateAssets="All"` attribute, but it will not hurt, in case you are
+repurposing the project at some time later. The important part is (1) tell the
+gRPC tools to select the whole directory of files; (2) order placement of each
+output besides its source, and (3) not compile the generated .cs files. Add the
+following stanza under the `<Project>` xml node:
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="**/*.proto" OutputDir="%(RelativePath)" CompileOutputs="false" />
+ </ItemGroup>
+```
+
+The `Include` tells the build system to recursively examine project directory
+and its subdirectories (`**`) include all files matching the wildcard `*.proto`.
+You can instead selectively include your files or selectively exclude files from
+the glob pattern; [MSBuild documentation explains
+that](https://docs.microsoft.com/visualstudio/msbuild/msbuild-items). The
+`OutputDir="%(RelativePath)"` orders the output directory for each .cs file be
+same as the corresponding .proto directory. Finally, `CompileOutputs="false"`
+prevents compiling the generated files into an assembly.
+
+Note that an empty assembly is still generated, but you should ignore it. As
+with any build system, it is used to detect out-of-date dependencies and
+recompile them.
+
+#### I am getting a warning about a missing expected file!
+
+When we are preparing compile, there is no way to know whether a given proto
+file will produce a *Grpc.cs output or not. If the proto file has a `service`
+clause, it will; otherwise, it won't, but the build script cannot know that in
+advance. When we are treating generated .cs files as temporary, this is ok, but
+when generating them for you, creating empty files is probably not. You need to
+tell the compiler which files should be compiled with gRPC services, and which
+only contain protobuffer message definitions.
+
+One option is just ignore the warning. Another is quench it by setting the
+property `Protobuf_NoWarnMissingExpected` to `true`:
+
+```xml
+<PropertyGroup>
+ <Protobuf_NoWarnMissingExpected>true</Protobuf_NoWarnMissingExpected>
+</PropertyGroup>
+```
+
+For a small to medium projects this is sufficient. But because of a missing
+output dependency, the corresponding .proto file will be recompiled on every
+build. If your project is large, or if other large builds depend on generated
+files, and are also needlessly recompiled, you'll want to prevent these rebuilds
+when files have not in fact changed, as follows:
+
+##### Explicitly tell protoc for which files it should use the gRPC plugin
+
+You need to set the `Protobuf` item property `GrpcServices` to `None` for those
+.proto inputs which do not have a `service` declared (or, optionally, those
+which do but you do not want a service/client stub for). The default value for
+the `GrpcServices` is `Both` (both client and server stub are generated). This
+is easy enough to do with glob patterns if your files are laid out in
+directories according to their service use, for example:
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="**/*.proto" OutputDir="%(RelativePath)"
+ CompileOutputs="false" GrpcServices="None" />
+ <Protobuf Update="**/hello/*.proto;**/bye/*.proto" GrpcServices="Both" />
+ </ItemGroup>
+```
+
+In this sample, all .proto files are compiled with `GrpcServices="None"`, except
+for .proto files in subdirectories on any tree level named `hello/` and `bye`,
+which will take `GrpcServices="Both"` Note the use of the `Update` attribute
+instead of `Include`. If you write `Include` by mistake, the files will be added
+to compile *twice*, once with, and once without GrpcServices. Pay attention not
+to do that!
+
+Another example would be the use of globbing if your service .proto files are
+named according to a pattern, for example `*_services.proto`. In this case, The
+`Update` attribute can be written as `Update="**/*_service.proto"`, to set the
+attribute `GrpcServices="Both"` only on these files.
+
+But what if no patterns work, and you cannot sort a large set of .proto file
+into those containing a service and those not? As a last resort,
+
+##### Force creating empty .cs files for missing outputs.
+
+Naturally, this results in a dirtier compiler output tree, but you may clean it
+using other ways (for example, by not copying zero-length .cs files to their
+final destination). Remember, though, that the files are still important to keep
+in their output locations to prevent needless recompilation. You may force
+generating empty files by setting the property `Protobuf_TouchMissingExpected`
+to `true`:
+
+```xml
+ <PropertyGroup>
+ <Protobuf_TouchMissingExpected>true</Protobuf_TouchMissingExpected>
+ </PropertyGroup>
+```
+
+#### But I do not use gRPC at all, I need only protobuffer messages compiled
+
+Set `GrpcServices="None"` on all proto files:
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="**/*.proto" OutputDir="%(RelativeDir)"
+ CompileOutputs="false" GrpcServices="None" />
+ </ItemGroup>
+```
+
+#### That's good so far, but I do not want the `bin` and `obj` directories in my tree
+
+You may create the project in a subdirectory of the root of your files, such as,
+for example, `.build`. In this case, you want to refer to the proto files
+relative to that `.build/` directory as
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="../**/*.proto" ProtoRoot=".."
+ OutputDir="%(RelativeDir)" CompileOutputs="false" />
+ </ItemGroup>
+```
+
+Pay attention to the `ProtoRoot` property. It needs to be set to the directory
+where `import` declarations in the .proto files are looking for files, since the
+project root is no longer the same as the proto root.
+
+Alternatively, you may place the project in a directory *above* your proto root,
+and refer to the files with a subdirectory name:
+
+```xml
+ <ItemGroup>
+ <Protobuf Include="proto_root/**/*.proto" ProtoRoot="proto_root"
+ OutputDir="%(RelativeDir)" CompileOutputs="false" />
+ </ItemGroup>
+```
+
+### Alas, this all is nice, but my scenario is more complex, -OR-
+### I'll investigate that when I have time. I just want to run protoc as I did before.
+
+One option is examine our [.targets and .props files](Grpc.Tools/build/) and see
+if you can create your own build sequence from the provided targets so that it
+fits your needs. Also please open an issue (and tag @kkm000 in it!) with your
+scenario. We'll try to support it if it appears general enough.
+
+But if you just want to run `protoc` using MsBuild `<Exec>` task, as you
+probably did before the version 1.17 of Grpc.Tools, we have a few build
+variables that point to resolved names of tools and common protoc imports.
+You'll have to roll your own dependency checking (or go with a full
+recompilation each time, if that works for you), but at the very least each
+version of the Tools package will point to the correct location of the files,
+and resolve the compiler and plugin executables appropriate for the host system.
+These property variables are:
+
+* `Protobuf_ProtocFullPath` points to the full path and filename of protoc executable, e. g.,
+ "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\bin\windows\protoc.exe".
+
+* `gRPC_PluginFullPath` points to the full path and filename of gRPC plugin, such as
+ "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\bin\windows\grpc_csharp_plugin.exe"
+
+* `Protobuf_StandardImportsPath` points to the standard proto import directory, for example,
+ "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\include". This is
+ the directory where a declaration such as `import "google/protobuf/wrappers.proto";`
+ in a proto file would find its target.
+
+Use MSBuild property expansion syntax `$(VariableName)` in your protoc command
+line to substitute these variables, for instance,
+
+```xml
+ <Target Name="MyProtoCompile">
+ <PropertyGroup>
+ <ProtoCCommand>$(Protobuf_ProtocFullPath) --plugin=protoc-gen-grpc=$(gRPC_PluginFullPath) -I $(Protobuf_StandardImportsPath) ....rest of your command.... </ProtoCCommand>
+ </PropertyGroup>
+ <Message Importance="high" Text="$(ProtoCCommand)" />
+ <Exec Command="$(ProtoCCommand)" />
+ </Target>
+```
+
+Also make sure *not* to include any file names to the `Protobuf` item
+collection, otherwise they will be compiled by default. If, by any chance, you
+used that name for your build scripting, you must rename it.
+
+### What about C++ projects?
+
+This is in the works. Currently, the same variables as above are set to point to
+the protoc binary, C++ gRPC plugin and the standard imports, but nothing else.
+Do not use the `Protobuf` item collection name so that your project remains
+future-proof. We'll use it for C++ projects too.
+
+Reference
+---------
+
+### Protobuf item metadata reference
+
+The following metadata are recognized on the `<Protobuf>` items.
+
+| Name | Default | Value | Synopsis |
+|----------------|-----------|----------------------|----------------------------------|
+| Access | `public` | `public`, `internal` | Generated class access |
+| ProtoCompile | `true` | `true`, `false` | Pass files to protoc? |
+| ProtoRoot | See notes | A directory | Common root for set of files |
+| CompileOutputs | `true` | `true`, `false` | C#-compile generated files? |
+| OutputDir | See notes | A directory | Directory for generated C# files |
+| GrpcOutputDir | See notes | A directory | Directory for generated stubs |
+| GrpcServices | `both` | `none`, `client`, | Generated gRPC stubs |
+| | | `server`, `both` | |
+
+__Notes__
+
+* __ProtoRoot__
+For files _inside_ the project cone, `ProtoRoot` is set by default to the
+project directory. For every file _outside_ of the project directory, the value
+is set to this file's containing directory name, individually per file. If you
+include a subtree of proto files that lies outside of the project directory, you
+need to set this metadatum. There is an example in this file above. The path in
+this variable is relative to the project directory.
+
+* __OutputDir__
+The default value for this metadatum is the value of the property
+`Protobuf_OutputPath`. This property, in turn, unless you set it in your
+project, will be set to the value of the standard MSBuild property
+`IntermediateOutputPath`, which points to the location of compilation object
+outputs, such as "obj/Release/netstandard1.5/". The path in this property is
+considered relative to the project directory.
+
+* __GrpcOutputDir__
+Unless explicitly set, will follow `OutputDir` for any given file.
+
+* __Access__
+Sets generated class access on _both_ generated message and gRPC stub classes.
diff --git a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
index 3a161763fd..b10d7a1045 100644
--- a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
+++ b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
@@ -25,7 +25,7 @@ namespace Grpc.Core.Tests
{
public class AppDomainUnloadTest
{
-#if NETCOREAPP1_0
+#if NETCOREAPP1_1 || NETCOREAPP2_1
[Test]
[Ignore("Not supported for CoreCLR")]
public void AppDomainUnloadHookCanCleanupAbandonedCall()
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index d58f046824..178931a3d7 100755
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Core.Tests</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Core.Tests</PackageId>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
index e7d8939978..5c7d48f786 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
@@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall = new FakeNativeCall();
asyncCallServer = new AsyncCallServer<string, string>(
- Marshallers.StringMarshaller.Serializer, Marshallers.StringMarshaller.Deserializer,
+ Marshallers.StringMarshaller.ContextualSerializer, Marshallers.StringMarshaller.ContextualDeserializer,
server);
asyncCallServer.InitializeForTesting(fakeCall);
}
diff --git a/src/csharp/Grpc.Core.Tests/MarshallerTest.cs b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs
index 97f64a0575..ad3e81d61f 100644
--- a/src/csharp/Grpc.Core.Tests/MarshallerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs
@@ -69,11 +69,8 @@ namespace Grpc.Core.Tests
Assert.AreSame(contextualSerializer, marshaller.ContextualSerializer);
Assert.AreSame(contextualDeserializer, marshaller.ContextualDeserializer);
-
- // test that emulated serializer and deserializer work
- var origMsg = "abc";
- var serialized = marshaller.Serializer(origMsg);
- Assert.AreEqual(origMsg, marshaller.Deserializer(serialized));
+ Assert.Throws(typeof(NotImplementedException), () => marshaller.Serializer("abc"));
+ Assert.Throws(typeof(NotImplementedException), () => marshaller.Deserializer(new byte[] {1, 2, 3}));
}
class FakeSerializationContext : SerializationContext
diff --git a/src/csharp/Grpc.Core.Tests/NUnitMain.cs b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
index 49cb8cd3b9..3b206603f1 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
@@ -34,11 +34,7 @@ namespace Grpc.Core.Tests
{
// Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
GrpcEnvironment.SetLogger(new ConsoleLogger());
-#if NETCOREAPP1_0
- return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
-#else
- return new AutoRun().Execute(args);
-#endif
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 0904453b6e..f785f70f4c 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -31,7 +31,7 @@ namespace Grpc.Core.Tests
public class SanityTest
{
// TODO: make sanity test work for CoreCLR as well
-#if !NETCOREAPP1_0
+#if !NETCOREAPP1_1 && !NETCOREAPP2_1
/// <summary>
/// Because we depend on a native library, sometimes when things go wrong, the
/// entire NUnit test process crashes. To be able to track down problems better,
@@ -44,7 +44,7 @@ namespace Grpc.Core.Tests
public void TestsJsonUpToDate()
{
var discoveredTests = DiscoverAllTestClasses();
- var testsFromFile
+ var testsFromFile
= JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(ReadTestsJson());
Assert.AreEqual(discoveredTests, testsFromFile);
diff --git a/src/csharp/Grpc.Core/DeserializationContext.cs b/src/csharp/Grpc.Core/DeserializationContext.cs
index 5b6372ef85..d69e0db5bd 100644
--- a/src/csharp/Grpc.Core/DeserializationContext.cs
+++ b/src/csharp/Grpc.Core/DeserializationContext.cs
@@ -16,6 +16,8 @@
#endregion
+using System;
+
namespace Grpc.Core
{
/// <summary>
@@ -41,6 +43,9 @@ namespace Grpc.Core
/// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so.
/// </summary>
/// <returns>byte array containing the entire payload.</returns>
- public abstract byte[] PayloadAsNewBuffer();
+ public virtual byte[] PayloadAsNewBuffer()
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 4cdf0ee6a7..b6d687f71e 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -54,7 +54,7 @@ namespace Grpc.Core.Internal
ClientSideStatus? finishedStatus;
public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
- : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
+ : base(callDetails.RequestMarshaller.ContextualSerializer, callDetails.ResponseMarshaller.ContextualDeserializer)
{
this.details = callDetails.WithOptions(callDetails.Options.Normalize());
this.initialMetadataSent = true; // we always send metadata at the very beginning of the call.
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index a93dc34620..39c9f7c616 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -40,8 +40,8 @@ namespace Grpc.Core.Internal
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message.");
- readonly Func<TWrite, byte[]> serializer;
- readonly Func<byte[], TRead> deserializer;
+ readonly Action<TWrite, SerializationContext> serializer;
+ readonly Func<DeserializationContext, TRead> deserializer;
protected readonly object myLock = new object();
@@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
protected bool initialMetadataSent;
protected long streamingWritesCounter; // Number of streaming send operations started so far.
- public AsyncCallBase(Func<TWrite, byte[]> serializer, Func<byte[], TRead> deserializer)
+ public AsyncCallBase(Action<TWrite, SerializationContext> serializer, Func<DeserializationContext, TRead> deserializer)
{
this.serializer = GrpcPreconditions.CheckNotNull(serializer);
this.deserializer = GrpcPreconditions.CheckNotNull(deserializer);
@@ -215,14 +215,26 @@ namespace Grpc.Core.Internal
protected byte[] UnsafeSerialize(TWrite msg)
{
- return serializer(msg);
+ DefaultSerializationContext context = null;
+ try
+ {
+ context = DefaultSerializationContext.GetInitializedThreadLocal();
+ serializer(msg, context);
+ return context.GetPayload();
+ }
+ finally
+ {
+ context?.Reset();
+ }
}
protected Exception TryDeserialize(byte[] payload, out TRead msg)
{
+ DefaultDeserializationContext context = null;
try
{
- msg = deserializer(payload);
+ context = DefaultDeserializationContext.GetInitializedThreadLocal(payload);
+ msg = deserializer(context);
return null;
}
catch (Exception e)
@@ -230,6 +242,11 @@ namespace Grpc.Core.Internal
msg = default(TRead);
return e;
}
+ finally
+ {
+ context?.Reset();
+
+ }
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 0ceca4abb8..0bf1fb3b7d 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -37,7 +37,7 @@ namespace Grpc.Core.Internal
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
readonly Server server;
- public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, Server server) : base(serializer, deserializer)
+ public AsyncCallServer(Action<TResponse, SerializationContext> serializer, Func<DeserializationContext, TRequest> deserializer, Server server) : base(serializer, deserializer)
{
this.server = GrpcPreconditions.CheckNotNull(server);
}
diff --git a/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
new file mode 100644
index 0000000000..7ace80e8d5
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
@@ -0,0 +1,66 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Grpc.Core.Utils;
+using System;
+using System.Threading;
+
+namespace Grpc.Core.Internal
+{
+ internal class DefaultDeserializationContext : DeserializationContext
+ {
+ static readonly ThreadLocal<DefaultDeserializationContext> threadLocalInstance =
+ new ThreadLocal<DefaultDeserializationContext>(() => new DefaultDeserializationContext(), false);
+
+ byte[] payload;
+ bool alreadyCalledPayloadAsNewBuffer;
+
+ public DefaultDeserializationContext()
+ {
+ Reset();
+ }
+
+ public override int PayloadLength => payload.Length;
+
+ public override byte[] PayloadAsNewBuffer()
+ {
+ GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer);
+ alreadyCalledPayloadAsNewBuffer = true;
+ return payload;
+ }
+
+ public void Initialize(byte[] payload)
+ {
+ this.payload = GrpcPreconditions.CheckNotNull(payload);
+ this.alreadyCalledPayloadAsNewBuffer = false;
+ }
+
+ public void Reset()
+ {
+ this.payload = null;
+ this.alreadyCalledPayloadAsNewBuffer = true; // mark payload as read
+ }
+
+ public static DefaultDeserializationContext GetInitializedThreadLocal(byte[] payload)
+ {
+ var instance = threadLocalInstance.Value;
+ instance.Initialize(payload);
+ return instance;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/DefaultSerializationContext.cs b/src/csharp/Grpc.Core/Internal/DefaultSerializationContext.cs
new file mode 100644
index 0000000000..cceb194879
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultSerializationContext.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Grpc.Core.Utils;
+using System.Threading;
+
+namespace Grpc.Core.Internal
+{
+ internal class DefaultSerializationContext : SerializationContext
+ {
+ static readonly ThreadLocal<DefaultSerializationContext> threadLocalInstance =
+ new ThreadLocal<DefaultSerializationContext>(() => new DefaultSerializationContext(), false);
+
+ bool isComplete;
+ byte[] payload;
+
+ public DefaultSerializationContext()
+ {
+ Reset();
+ }
+
+ public override void Complete(byte[] payload)
+ {
+ GrpcPreconditions.CheckState(!isComplete);
+ this.isComplete = true;
+ this.payload = payload;
+ }
+
+ internal byte[] GetPayload()
+ {
+ return this.payload;
+ }
+
+ public void Reset()
+ {
+ this.isComplete = false;
+ this.payload = null;
+ }
+
+ public static DefaultSerializationContext GetInitializedThreadLocal()
+ {
+ var instance = threadLocalInstance.Value;
+ instance.Reset();
+ return instance;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index f526b913af..5177b69fd9 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -83,13 +83,13 @@ namespace Grpc.Core.Internal
// See https://github.com/grpc/grpc/pull/7303 for one option.
var assemblyDirectory = Path.GetDirectoryName(GetAssemblyPath());
- // With old-style VS projects, the native libraries get copied using a .targets rule to the build output folder
+ // With "classic" VS projects, the native libraries get copied using a .targets rule to the build output folder
// alongside the compiled assembly.
// With dotnet cli projects targeting net45 framework, the native libraries (just the required ones)
// are similarly copied to the built output folder, through the magic of Microsoft.NETCore.Platforms.
var classicPath = Path.Combine(assemblyDirectory, GetNativeLibraryFilename());
- // With dotnet cli project targeting netcoreapp1.0, projects will use Grpc.Core assembly directly in the location where it got restored
+ // With dotnet cli project targeting netcoreappX.Y, projects will use Grpc.Core assembly directly in the location where it got restored
// by nuget. We locate the native libraries based on known structure of Grpc.Core nuget package.
// When "dotnet publish" is used, the runtimes directory is copied next to the published assemblies.
string runtimesDirectory = string.Format("runtimes/{0}/native", GetPlatformString());
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 81522cf8fe..ec732e8c7f 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -52,8 +52,8 @@ namespace Grpc.Core.Internal
public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
- method.ResponseMarshaller.Serializer,
- method.RequestMarshaller.Deserializer,
+ method.ResponseMarshaller.ContextualSerializer,
+ method.RequestMarshaller.ContextualDeserializer,
newRpc.Server);
asyncCall.Initialize(newRpc.Call, cq);
@@ -116,8 +116,8 @@ namespace Grpc.Core.Internal
public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
- method.ResponseMarshaller.Serializer,
- method.RequestMarshaller.Deserializer,
+ method.ResponseMarshaller.ContextualSerializer,
+ method.RequestMarshaller.ContextualDeserializer,
newRpc.Server);
asyncCall.Initialize(newRpc.Call, cq);
@@ -179,8 +179,8 @@ namespace Grpc.Core.Internal
public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
- method.ResponseMarshaller.Serializer,
- method.RequestMarshaller.Deserializer,
+ method.ResponseMarshaller.ContextualSerializer,
+ method.RequestMarshaller.ContextualDeserializer,
newRpc.Server);
asyncCall.Initialize(newRpc.Call, cq);
@@ -242,8 +242,8 @@ namespace Grpc.Core.Internal
public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
- method.ResponseMarshaller.Serializer,
- method.RequestMarshaller.Deserializer,
+ method.ResponseMarshaller.ContextualSerializer,
+ method.RequestMarshaller.ContextualDeserializer,
newRpc.Server);
asyncCall.Initialize(newRpc.Call, cq);
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 0af9aa586b..34a1849cd7 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -41,6 +41,8 @@ namespace Grpc.Core
{
this.serializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
+ // contextual serialization/deserialization is emulated to make the marshaller
+ // usable with the grpc library (required for backward compatibility).
this.contextualSerializer = EmulateContextualSerializer;
this.contextualDeserializer = EmulateContextualDeserializer;
}
@@ -57,10 +59,10 @@ namespace Grpc.Core
{
this.contextualSerializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
this.contextualDeserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
- // TODO(jtattermusch): once gRPC C# library switches to using contextual (de)serializer,
- // emulating the simple (de)serializer will become unnecessary.
- this.serializer = EmulateSimpleSerializer;
- this.deserializer = EmulateSimpleDeserializer;
+ // gRPC only uses contextual serializer/deserializer internally, so emulating the legacy
+ // (de)serializer is not necessary.
+ this.serializer = (msg) => { throw new NotImplementedException(); };
+ this.deserializer = (payload) => { throw new NotImplementedException(); };
}
/// <summary>
@@ -85,25 +87,6 @@ namespace Grpc.Core
/// </summary>
public Func<DeserializationContext, T> ContextualDeserializer => this.contextualDeserializer;
- // for backward compatibility, emulate the simple serializer using the contextual one
- private byte[] EmulateSimpleSerializer(T msg)
- {
- // TODO(jtattermusch): avoid the allocation by passing a thread-local instance
- // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer.
- var context = new EmulatedSerializationContext();
- this.contextualSerializer(msg, context);
- return context.GetPayload();
- }
-
- // for backward compatibility, emulate the simple deserializer using the contextual one
- private T EmulateSimpleDeserializer(byte[] payload)
- {
- // TODO(jtattermusch): avoid the allocation by passing a thread-local instance
- // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer.
- var context = new EmulatedDeserializationContext(payload);
- return this.contextualDeserializer(context);
- }
-
// for backward compatibility, emulate the contextual serializer using the simple one
private void EmulateContextualSerializer(T message, SerializationContext context)
{
@@ -116,44 +99,6 @@ namespace Grpc.Core
{
return this.deserializer(context.PayloadAsNewBuffer());
}
-
- internal class EmulatedSerializationContext : SerializationContext
- {
- bool isComplete;
- byte[] payload;
-
- public override void Complete(byte[] payload)
- {
- GrpcPreconditions.CheckState(!isComplete);
- this.isComplete = true;
- this.payload = payload;
- }
-
- internal byte[] GetPayload()
- {
- return this.payload;
- }
- }
-
- internal class EmulatedDeserializationContext : DeserializationContext
- {
- readonly byte[] payload;
- bool alreadyCalledPayloadAsNewBuffer;
-
- public EmulatedDeserializationContext(byte[] payload)
- {
- this.payload = GrpcPreconditions.CheckNotNull(payload);
- }
-
- public override int PayloadLength => payload.Length;
-
- public override byte[] PayloadAsNewBuffer()
- {
- GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer);
- alreadyCalledPayloadAsNewBuffer = true;
- return payload;
- }
- }
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/SerializationContext.cs b/src/csharp/Grpc.Core/SerializationContext.cs
index cf4d1595da..9aef2adbcd 100644
--- a/src/csharp/Grpc.Core/SerializationContext.cs
+++ b/src/csharp/Grpc.Core/SerializationContext.cs
@@ -16,6 +16,8 @@
#endregion
+using System;
+
namespace Grpc.Core
{
/// <summary>
@@ -29,6 +31,9 @@ namespace Grpc.Core
/// payload which must not be accessed afterwards.
/// </summary>
/// <param name="payload">the serialized form of current message</param>
- public abstract void Complete(byte[] payload);
+ public virtual void Complete(byte[] payload)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index 07c6aa1796..b040ab379c 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -72,7 +72,7 @@ namespace Grpc.Core
}
/// <summary>
- /// Adds a definitions for a single request - single response method.
+ /// Adds a definition for a single request - single response method.
/// </summary>
/// <typeparam name="TRequest">The request message class.</typeparam>
/// <typeparam name="TResponse">The response message class.</typeparam>
@@ -90,7 +90,7 @@ namespace Grpc.Core
}
/// <summary>
- /// Adds a definitions for a client streaming method.
+ /// Adds a definition for a client streaming method.
/// </summary>
/// <typeparam name="TRequest">The request message class.</typeparam>
/// <typeparam name="TResponse">The response message class.</typeparam>
@@ -108,7 +108,7 @@ namespace Grpc.Core
}
/// <summary>
- /// Adds a definitions for a server streaming method.
+ /// Adds a definition for a server streaming method.
/// </summary>
/// <typeparam name="TRequest">The request message class.</typeparam>
/// <typeparam name="TResponse">The response message class.</typeparam>
@@ -126,7 +126,7 @@ namespace Grpc.Core
}
/// <summary>
- /// Adds a definitions for a bidirectional streaming method.
+ /// Adds a definition for a bidirectional streaming method.
/// </summary>
/// <typeparam name="TRequest">The request message class.</typeparam>
/// <typeparam name="TResponse">The response message class.</typeparam>
diff --git a/src/csharp/Grpc.Core/ServiceBinderBase.cs b/src/csharp/Grpc.Core/ServiceBinderBase.cs
new file mode 100644
index 0000000000..d4909f4a26
--- /dev/null
+++ b/src/csharp/Grpc.Core/ServiceBinderBase.cs
@@ -0,0 +1,101 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Grpc.Core.Interceptors;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Allows binding server-side method implementations in alternative serving stacks.
+ /// Instances of this class are usually populated by the <c>BindService</c> method
+ /// that is part of the autogenerated code for a protocol buffers service definition.
+ /// <seealso cref="ServerServiceDefinition"/>
+ /// </summary>
+ public class ServiceBinderBase
+ {
+ /// <summary>
+ /// Adds a definition for a single request - single response method.
+ /// </summary>
+ /// <typeparam name="TRequest">The request message class.</typeparam>
+ /// <typeparam name="TResponse">The response message class.</typeparam>
+ /// <param name="method">The method.</param>
+ /// <param name="handler">The method handler.</param>
+ public virtual void AddMethod<TRequest, TResponse>(
+ Method<TRequest, TResponse> method,
+ UnaryServerMethod<TRequest, TResponse> handler)
+ where TRequest : class
+ where TResponse : class
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Adds a definition for a client streaming method.
+ /// </summary>
+ /// <typeparam name="TRequest">The request message class.</typeparam>
+ /// <typeparam name="TResponse">The response message class.</typeparam>
+ /// <param name="method">The method.</param>
+ /// <param name="handler">The method handler.</param>
+ public virtual void AddMethod<TRequest, TResponse>(
+ Method<TRequest, TResponse> method,
+ ClientStreamingServerMethod<TRequest, TResponse> handler)
+ where TRequest : class
+ where TResponse : class
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Adds a definition for a server streaming method.
+ /// </summary>
+ /// <typeparam name="TRequest">The request message class.</typeparam>
+ /// <typeparam name="TResponse">The response message class.</typeparam>
+ /// <param name="method">The method.</param>
+ /// <param name="handler">The method handler.</param>
+ public virtual void AddMethod<TRequest, TResponse>(
+ Method<TRequest, TResponse> method,
+ ServerStreamingServerMethod<TRequest, TResponse> handler)
+ where TRequest : class
+ where TResponse : class
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Adds a definition for a bidirectional streaming method.
+ /// </summary>
+ /// <typeparam name="TRequest">The request message class.</typeparam>
+ /// <typeparam name="TResponse">The response message class.</typeparam>
+ /// <param name="method">The method.</param>
+ /// <param name="handler">The method handler.</param>
+ public virtual void AddMethod<TRequest, TResponse>(
+ Method<TRequest, TResponse> method,
+ DuplexStreamingServerMethod<TRequest, TResponse> handler)
+ where TRequest : class
+ where TResponse : class
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index ed0d884365..4fffe4f644 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
- <GrpcCsharpVersion>1.17.0-dev</GrpcCsharpVersion>
+ <GrpcCsharpVersion>1.18.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 14714c8c4a..633880189c 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.17.0.0";
+ public const string CurrentAssemblyFileVersion = "1.18.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.17.0-dev";
+ public const string CurrentVersion = "1.18.0-dev";
}
}
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index db4e3ef4e3..1afcd9fba0 100755
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Examples.MathClient</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Examples.MathClient</PackageId>
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index b12b418d01..75ef6d1008 100755
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Examples.MathServer</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Examples.MathServer</PackageId>
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 7493eb8051..93d112a0c5 100755
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Examples.Tests</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Examples.Tests</PackageId>
diff --git a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
index bcb8b46b64..107df64809 100644
--- a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
@@ -34,11 +34,7 @@ namespace Grpc.Examples.Tests
{
// Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
GrpcEnvironment.SetLogger(new ConsoleLogger());
-#if NETCOREAPP1_0
- return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
-#else
- return new AutoRun().Execute(args);
-#endif
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
}
}
}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index baa3b4ce6c..9ce2b59d03 100755
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Examples</AssemblyName>
<PackageId>Grpc.Examples</PackageId>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index 9578bb4d81..e5be387e67 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -287,6 +287,18 @@ namespace Math {
.AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, MathBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_Div, serviceImpl.Div);
+ serviceBinder.AddMethod(__Method_DivMany, serviceImpl.DivMany);
+ serviceBinder.AddMethod(__Method_Fib, serviceImpl.Fib);
+ serviceBinder.AddMethod(__Method_Sum, serviceImpl.Sum);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index 616e56df10..2a037a72e5 100755
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.HealthCheck.Tests</PackageId>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
index 365551e895..db6d32a5b2 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
@@ -34,11 +34,7 @@ namespace Grpc.HealthCheck.Tests
{
// Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
GrpcEnvironment.SetLogger(new ConsoleLogger());
-#if NETCOREAPP1_0
- return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
-#else
- return new AutoRun().Execute(args);
-#endif
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
}
}
}
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
index a90f261d28..2c3bb45c3c 100644
--- a/src/csharp/Grpc.HealthCheck/Health.cs
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -25,15 +25,17 @@ namespace Grpc.Health.V1 {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChtncnBjL2hlYWx0aC92MS9oZWFsdGgucHJvdG8SDmdycGMuaGVhbHRoLnYx",
- "IiUKEkhlYWx0aENoZWNrUmVxdWVzdBIPCgdzZXJ2aWNlGAEgASgJIpQBChNI",
+ "IiUKEkhlYWx0aENoZWNrUmVxdWVzdBIPCgdzZXJ2aWNlGAEgASgJIqkBChNI",
"ZWFsdGhDaGVja1Jlc3BvbnNlEkEKBnN0YXR1cxgBIAEoDjIxLmdycGMuaGVh",
- "bHRoLnYxLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0YXR1cyI6Cg1T",
+ "bHRoLnYxLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0YXR1cyJPCg1T",
"ZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5HEAESDwoLTk9U",
- "X1NFUlZJTkcQAjJaCgZIZWFsdGgSUAoFQ2hlY2sSIi5ncnBjLmhlYWx0aC52",
- "MS5IZWFsdGhDaGVja1JlcXVlc3QaIy5ncnBjLmhlYWx0aC52MS5IZWFsdGhD",
- "aGVja1Jlc3BvbnNlQmEKEWlvLmdycGMuaGVhbHRoLnYxQgtIZWFsdGhQcm90",
- "b1ABWixnb29nbGUuZ29sYW5nLm9yZy9ncnBjL2hlYWx0aC9ncnBjX2hlYWx0",
- "aF92MaoCDkdycGMuSGVhbHRoLlYxYgZwcm90bzM="));
+ "X1NFUlZJTkcQAhITCg9TRVJWSUNFX1VOS05PV04QAzKuAQoGSGVhbHRoElAK",
+ "BUNoZWNrEiIuZ3JwYy5oZWFsdGgudjEuSGVhbHRoQ2hlY2tSZXF1ZXN0GiMu",
+ "Z3JwYy5oZWFsdGgudjEuSGVhbHRoQ2hlY2tSZXNwb25zZRJSCgVXYXRjaBIi",
+ "LmdycGMuaGVhbHRoLnYxLkhlYWx0aENoZWNrUmVxdWVzdBojLmdycGMuaGVh",
+ "bHRoLnYxLkhlYWx0aENoZWNrUmVzcG9uc2UwAUJhChFpby5ncnBjLmhlYWx0",
+ "aC52MUILSGVhbHRoUHJvdG9QAVosZ29vZ2xlLmdvbGFuZy5vcmcvZ3JwYy9o",
+ "ZWFsdGgvZ3JwY19oZWFsdGhfdjGqAg5HcnBjLkhlYWx0aC5WMWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -309,6 +311,10 @@ namespace Grpc.Health.V1 {
[pbr::OriginalName("UNKNOWN")] Unknown = 0,
[pbr::OriginalName("SERVING")] Serving = 1,
[pbr::OriginalName("NOT_SERVING")] NotServing = 2,
+ /// <summary>
+ /// Used only by the Watch method.
+ /// </summary>
+ [pbr::OriginalName("SERVICE_UNKNOWN")] ServiceUnknown = 3,
}
}
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 5e79c04d2a..51956f2f23 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -40,6 +40,13 @@ namespace Grpc.Health.V1 {
__Marshaller_grpc_health_v1_HealthCheckRequest,
__Marshaller_grpc_health_v1_HealthCheckResponse);
+ static readonly grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse> __Method_Watch = new grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse>(
+ grpc::MethodType.ServerStreaming,
+ __ServiceName,
+ "Watch",
+ __Marshaller_grpc_health_v1_HealthCheckRequest,
+ __Marshaller_grpc_health_v1_HealthCheckResponse);
+
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
@@ -49,11 +56,44 @@ namespace Grpc.Health.V1 {
/// <summary>Base class for server-side implementations of Health</summary>
public abstract partial class HealthBase
{
+ /// <summary>
+ /// If the requested service is unknown, the call will fail with status
+ /// NOT_FOUND.
+ /// </summary>
+ /// <param name="request">The request received from the client.</param>
+ /// <param name="context">The context of the server-side call handler being invoked.</param>
+ /// <returns>The response to send back to the client (wrapped by a task).</returns>
public virtual global::System.Threading.Tasks.Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Performs a watch for the serving status of the requested service.
+ /// The server will immediately send back a message indicating the current
+ /// serving status. It will then subsequently send a new message whenever
+ /// the service's serving status changes.
+ ///
+ /// If the requested service is unknown when the call is received, the
+ /// server will send a message setting the serving status to
+ /// SERVICE_UNKNOWN but will *not* terminate the call. If at some
+ /// future point, the serving status of the service becomes known, the
+ /// server will send a new message with the service's serving status.
+ ///
+ /// If the call terminates with status UNIMPLEMENTED, then clients
+ /// should assume this method is not supported and should not retry the
+ /// call. If the call terminates with any other status (including OK),
+ /// clients should retry the call with appropriate exponential backoff.
+ /// </summary>
+ /// <param name="request">The request received from the client.</param>
+ /// <param name="responseStream">Used for sending responses back to the client.</param>
+ /// <param name="context">The context of the server-side call handler being invoked.</param>
+ /// <returns>A task indicating completion of the handler.</returns>
+ public virtual global::System.Threading.Tasks.Task Watch(global::Grpc.Health.V1.HealthCheckRequest request, grpc::IServerStreamWriter<global::Grpc.Health.V1.HealthCheckResponse> responseStream, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
}
/// <summary>Client for Health</summary>
@@ -79,22 +119,104 @@ namespace Grpc.Health.V1 {
{
}
+ /// <summary>
+ /// If the requested service is unknown, the call will fail with status
+ /// NOT_FOUND.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+ /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+ /// <param name="cancellationToken">An optional token for canceling the call.</param>
+ /// <returns>The response received from the server.</returns>
public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Check(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// If the requested service is unknown, the call will fail with status
+ /// NOT_FOUND.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="options">The options for the call.</param>
+ /// <returns>The response received from the server.</returns>
public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Check, null, options, request);
}
+ /// <summary>
+ /// If the requested service is unknown, the call will fail with status
+ /// NOT_FOUND.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+ /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+ /// <param name="cancellationToken">An optional token for canceling the call.</param>
+ /// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CheckAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// If the requested service is unknown, the call will fail with status
+ /// NOT_FOUND.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="options">The options for the call.</param>
+ /// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_Check, null, options, request);
}
+ /// <summary>
+ /// Performs a watch for the serving status of the requested service.
+ /// The server will immediately send back a message indicating the current
+ /// serving status. It will then subsequently send a new message whenever
+ /// the service's serving status changes.
+ ///
+ /// If the requested service is unknown when the call is received, the
+ /// server will send a message setting the serving status to
+ /// SERVICE_UNKNOWN but will *not* terminate the call. If at some
+ /// future point, the serving status of the service becomes known, the
+ /// server will send a new message with the service's serving status.
+ ///
+ /// If the call terminates with status UNIMPLEMENTED, then clients
+ /// should assume this method is not supported and should not retry the
+ /// call. If the call terminates with any other status (including OK),
+ /// clients should retry the call with appropriate exponential backoff.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+ /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+ /// <param name="cancellationToken">An optional token for canceling the call.</param>
+ /// <returns>The call object.</returns>
+ public virtual grpc::AsyncServerStreamingCall<global::Grpc.Health.V1.HealthCheckResponse> Watch(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return Watch(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// Performs a watch for the serving status of the requested service.
+ /// The server will immediately send back a message indicating the current
+ /// serving status. It will then subsequently send a new message whenever
+ /// the service's serving status changes.
+ ///
+ /// If the requested service is unknown when the call is received, the
+ /// server will send a message setting the serving status to
+ /// SERVICE_UNKNOWN but will *not* terminate the call. If at some
+ /// future point, the serving status of the service becomes known, the
+ /// server will send a new message with the service's serving status.
+ ///
+ /// If the call terminates with status UNIMPLEMENTED, then clients
+ /// should assume this method is not supported and should not retry the
+ /// call. If the call terminates with any other status (including OK),
+ /// clients should retry the call with appropriate exponential backoff.
+ /// </summary>
+ /// <param name="request">The request to send to the server.</param>
+ /// <param name="options">The options for the call.</param>
+ /// <returns>The call object.</returns>
+ public virtual grpc::AsyncServerStreamingCall<global::Grpc.Health.V1.HealthCheckResponse> Watch(global::Grpc.Health.V1.HealthCheckRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncServerStreamingCall(__Method_Watch, null, options, request);
+ }
/// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
protected override HealthClient NewInstance(ClientBaseConfiguration configuration)
{
@@ -107,7 +229,18 @@ namespace Grpc.Health.V1 {
public static grpc::ServerServiceDefinition BindService(HealthBase serviceImpl)
{
return grpc::ServerServiceDefinition.CreateBuilder()
- .AddMethod(__Method_Check, serviceImpl.Check).Build();
+ .AddMethod(__Method_Check, serviceImpl.Check)
+ .AddMethod(__Method_Watch, serviceImpl.Watch).Build();
+ }
+
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, HealthBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_Check, serviceImpl.Check);
+ serviceBinder.AddMethod(__Method_Watch, serviceImpl.Watch);
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 35713156ea..1cd4b83e1e 100755
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.IntegrationTesting.Client</PackageId>
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
index 3ecefe3bc4..2890a7df58 100755
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.IntegrationTesting.QpsWorker</PackageId>
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 1092b2c21e..ee718958bc 100755
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.IntegrationTesting.Server</PackageId>
@@ -19,7 +19,7 @@
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
-
+
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs" />
</ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
index 22272547f6..99926497e4 100755
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.IntegrationTesting.StressClient</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.IntegrationTesting.StressClient</PackageId>
diff --git a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs
index b5738593f2..3431b5fa18 100644
--- a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs
@@ -324,6 +324,19 @@ namespace Grpc.Testing {
.AddMethod(__Method_StreamingBothWays, serviceImpl.StreamingBothWays).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, BenchmarkServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall);
+ serviceBinder.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall);
+ serviceBinder.AddMethod(__Method_StreamingFromClient, serviceImpl.StreamingFromClient);
+ serviceBinder.AddMethod(__Method_StreamingFromServer, serviceImpl.StreamingFromServer);
+ serviceBinder.AddMethod(__Method_StreamingBothWays, serviceImpl.StreamingBothWays);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs
index 6e00348451..368b86659a 100644
--- a/src/csharp/Grpc.IntegrationTesting/Control.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Control.cs
@@ -34,7 +34,7 @@ namespace Grpc.Testing {
"U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy",
"X2hvc3Rfb3ZlcnJpZGUYAiABKAkSEQoJY3JlZF90eXBlGAMgASgJIk0KCkNo",
"YW5uZWxBcmcSDAoEbmFtZRgBIAEoCRITCglzdHJfdmFsdWUYAiABKAlIABIT",
- "CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSLvBAoMQ2xpZW50Q29uZmln",
+ "CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSKiBQoMQ2xpZW50Q29uZmln",
"EhYKDnNlcnZlcl90YXJnZXRzGAEgAygJEi0KC2NsaWVudF90eXBlGAIgASgO",
"MhguZ3JwYy50ZXN0aW5nLkNsaWVudFR5cGUSNQoPc2VjdXJpdHlfcGFyYW1z",
"GAMgASgLMhwuZ3JwYy50ZXN0aW5nLlNlY3VyaXR5UGFyYW1zEiQKHG91dHN0",
@@ -48,59 +48,60 @@ namespace Grpc.Testing {
"GA4gASgFEhgKEG90aGVyX2NsaWVudF9hcGkYDyABKAkSLgoMY2hhbm5lbF9h",
"cmdzGBAgAygLMhguZ3JwYy50ZXN0aW5nLkNoYW5uZWxBcmcSFgoOdGhyZWFk",
"c19wZXJfY3EYESABKAUSGwoTbWVzc2FnZXNfcGVyX3N0cmVhbRgSIAEoBRIY",
- "ChB1c2VfY29hbGVzY2VfYXBpGBMgASgIIjgKDENsaWVudFN0YXR1cxIoCgVz",
- "dGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIVCgRNYXJr",
- "Eg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAYASABKAsy",
- "Gi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgCIAEoCzIS",
- "LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSL9AgoMU2VydmVyQ29u",
- "ZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5nLlNlcnZl",
- "clR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50ZXN0aW5n",
- "LlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVy",
- "X3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2Fk",
- "X2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnEhEK",
- "CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJEhYK",
- "DnRocmVhZHNfcGVyX2NxGAwgASgFEhwKE3Jlc291cmNlX3F1b3RhX3NpemUY",
- "6QcgASgFEi8KDGNoYW5uZWxfYXJncxjqByADKAsyGC5ncnBjLnRlc3Rpbmcu",
- "Q2hhbm5lbEFyZyJoCgpTZXJ2ZXJBcmdzEisKBXNldHVwGAEgASgLMhouZ3Jw",
- "Yy50ZXN0aW5nLlNlcnZlckNvbmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBj",
- "LnRlc3RpbmcuTWFya0gAQgkKB2FyZ3R5cGUiVQoMU2VydmVyU3RhdHVzEigK",
- "BXN0YXRzGAEgASgLMhkuZ3JwYy50ZXN0aW5nLlNlcnZlclN0YXRzEgwKBHBv",
- "cnQYAiABKAUSDQoFY29yZXMYAyABKAUiDQoLQ29yZVJlcXVlc3QiHQoMQ29y",
- "ZVJlc3BvbnNlEg0KBWNvcmVzGAEgASgFIgYKBFZvaWQi/QEKCFNjZW5hcmlv",
- "EgwKBG5hbWUYASABKAkSMQoNY2xpZW50X2NvbmZpZxgCIAEoCzIaLmdycGMu",
- "dGVzdGluZy5DbGllbnRDb25maWcSEwoLbnVtX2NsaWVudHMYAyABKAUSMQoN",
- "c2VydmVyX2NvbmZpZxgEIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJDb25m",
- "aWcSEwoLbnVtX3NlcnZlcnMYBSABKAUSFgoOd2FybXVwX3NlY29uZHMYBiAB",
- "KAUSGQoRYmVuY2htYXJrX3NlY29uZHMYByABKAUSIAoYc3Bhd25fbG9jYWxf",
- "d29ya2VyX2NvdW50GAggASgFIjYKCVNjZW5hcmlvcxIpCglzY2VuYXJpb3MY",
- "ASADKAsyFi5ncnBjLnRlc3RpbmcuU2NlbmFyaW8ihAQKFVNjZW5hcmlvUmVz",
- "dWx0U3VtbWFyeRILCgNxcHMYASABKAESGwoTcXBzX3Blcl9zZXJ2ZXJfY29y",
- "ZRgCIAEoARIaChJzZXJ2ZXJfc3lzdGVtX3RpbWUYAyABKAESGAoQc2VydmVy",
- "X3VzZXJfdGltZRgEIAEoARIaChJjbGllbnRfc3lzdGVtX3RpbWUYBSABKAES",
- "GAoQY2xpZW50X3VzZXJfdGltZRgGIAEoARISCgpsYXRlbmN5XzUwGAcgASgB",
- "EhIKCmxhdGVuY3lfOTAYCCABKAESEgoKbGF0ZW5jeV85NRgJIAEoARISCgps",
- "YXRlbmN5Xzk5GAogASgBEhMKC2xhdGVuY3lfOTk5GAsgASgBEhgKEHNlcnZl",
- "cl9jcHVfdXNhZ2UYDCABKAESJgoec3VjY2Vzc2Z1bF9yZXF1ZXN0c19wZXJf",
- "c2Vjb25kGA0gASgBEiIKGmZhaWxlZF9yZXF1ZXN0c19wZXJfc2Vjb25kGA4g",
- "ASgBEiAKGGNsaWVudF9wb2xsc19wZXJfcmVxdWVzdBgPIAEoARIgChhzZXJ2",
- "ZXJfcG9sbHNfcGVyX3JlcXVlc3QYECABKAESIgoac2VydmVyX3F1ZXJpZXNf",
- "cGVyX2NwdV9zZWMYESABKAESIgoaY2xpZW50X3F1ZXJpZXNfcGVyX2NwdV9z",
- "ZWMYEiABKAEigwMKDlNjZW5hcmlvUmVzdWx0EigKCHNjZW5hcmlvGAEgASgL",
- "MhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxhdGVuY2llcxgCIAEoCzIb",
- "LmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8KDGNsaWVudF9zdGF0cxgD",
- "IAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cxIvCgxzZXJ2ZXJfc3Rh",
- "dHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSFAoMc2VydmVy",
- "X2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsyIy5ncnBjLnRlc3Rpbmcu",
- "U2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVudF9zdWNjZXNzGAcgAygI",
- "EhYKDnNlcnZlcl9zdWNjZXNzGAggAygIEjkKD3JlcXVlc3RfcmVzdWx0cxgJ",
- "IAMoCzIgLmdycGMudGVzdGluZy5SZXF1ZXN0UmVzdWx0Q291bnQqQQoKQ2xp",
- "ZW50VHlwZRIPCgtTWU5DX0NMSUVOVBAAEhAKDEFTWU5DX0NMSUVOVBABEhAK",
- "DE9USEVSX0NMSUVOVBACKlsKClNlcnZlclR5cGUSDwoLU1lOQ19TRVJWRVIQ",
- "ABIQCgxBU1lOQ19TRVJWRVIQARIYChRBU1lOQ19HRU5FUklDX1NFUlZFUhAC",
- "EhAKDE9USEVSX1NFUlZFUhADKnIKB1JwY1R5cGUSCQoFVU5BUlkQABINCglT",
- "VFJFQU1JTkcQARIZChVTVFJFQU1JTkdfRlJPTV9DTElFTlQQAhIZChVTVFJF",
- "QU1JTkdfRlJPTV9TRVJWRVIQAxIXChNTVFJFQU1JTkdfQk9USF9XQVlTEARi",
- "BnByb3RvMw=="));
+ "ChB1c2VfY29hbGVzY2VfYXBpGBMgASgIEjEKKW1lZGlhbl9sYXRlbmN5X2Nv",
+ "bGxlY3Rpb25faW50ZXJ2YWxfbWlsbGlzGBQgASgFIjgKDENsaWVudFN0YXR1",
+ "cxIoCgVzdGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIV",
+ "CgRNYXJrEg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAY",
+ "ASABKAsyGi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgC",
+ "IAEoCzISLmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSL9AgoMU2Vy",
+ "dmVyQ29uZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5n",
+ "LlNlcnZlclR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50",
+ "ZXN0aW5nLlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNf",
+ "c2VydmVyX3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5w",
+ "YXlsb2FkX2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29u",
+ "ZmlnEhEKCWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsg",
+ "ASgJEhYKDnRocmVhZHNfcGVyX2NxGAwgASgFEhwKE3Jlc291cmNlX3F1b3Rh",
+ "X3NpemUY6QcgASgFEi8KDGNoYW5uZWxfYXJncxjqByADKAsyGC5ncnBjLnRl",
+ "c3RpbmcuQ2hhbm5lbEFyZyJoCgpTZXJ2ZXJBcmdzEisKBXNldHVwGAEgASgL",
+ "MhouZ3JwYy50ZXN0aW5nLlNlcnZlckNvbmZpZ0gAEiIKBG1hcmsYAiABKAsy",
+ "Ei5ncnBjLnRlc3RpbmcuTWFya0gAQgkKB2FyZ3R5cGUiVQoMU2VydmVyU3Rh",
+ "dHVzEigKBXN0YXRzGAEgASgLMhkuZ3JwYy50ZXN0aW5nLlNlcnZlclN0YXRz",
+ "EgwKBHBvcnQYAiABKAUSDQoFY29yZXMYAyABKAUiDQoLQ29yZVJlcXVlc3Qi",
+ "HQoMQ29yZVJlc3BvbnNlEg0KBWNvcmVzGAEgASgFIgYKBFZvaWQi/QEKCFNj",
+ "ZW5hcmlvEgwKBG5hbWUYASABKAkSMQoNY2xpZW50X2NvbmZpZxgCIAEoCzIa",
+ "LmdycGMudGVzdGluZy5DbGllbnRDb25maWcSEwoLbnVtX2NsaWVudHMYAyAB",
+ "KAUSMQoNc2VydmVyX2NvbmZpZxgEIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2",
+ "ZXJDb25maWcSEwoLbnVtX3NlcnZlcnMYBSABKAUSFgoOd2FybXVwX3NlY29u",
+ "ZHMYBiABKAUSGQoRYmVuY2htYXJrX3NlY29uZHMYByABKAUSIAoYc3Bhd25f",
+ "bG9jYWxfd29ya2VyX2NvdW50GAggASgFIjYKCVNjZW5hcmlvcxIpCglzY2Vu",
+ "YXJpb3MYASADKAsyFi5ncnBjLnRlc3RpbmcuU2NlbmFyaW8ihAQKFVNjZW5h",
+ "cmlvUmVzdWx0U3VtbWFyeRILCgNxcHMYASABKAESGwoTcXBzX3Blcl9zZXJ2",
+ "ZXJfY29yZRgCIAEoARIaChJzZXJ2ZXJfc3lzdGVtX3RpbWUYAyABKAESGAoQ",
+ "c2VydmVyX3VzZXJfdGltZRgEIAEoARIaChJjbGllbnRfc3lzdGVtX3RpbWUY",
+ "BSABKAESGAoQY2xpZW50X3VzZXJfdGltZRgGIAEoARISCgpsYXRlbmN5XzUw",
+ "GAcgASgBEhIKCmxhdGVuY3lfOTAYCCABKAESEgoKbGF0ZW5jeV85NRgJIAEo",
+ "ARISCgpsYXRlbmN5Xzk5GAogASgBEhMKC2xhdGVuY3lfOTk5GAsgASgBEhgK",
+ "EHNlcnZlcl9jcHVfdXNhZ2UYDCABKAESJgoec3VjY2Vzc2Z1bF9yZXF1ZXN0",
+ "c19wZXJfc2Vjb25kGA0gASgBEiIKGmZhaWxlZF9yZXF1ZXN0c19wZXJfc2Vj",
+ "b25kGA4gASgBEiAKGGNsaWVudF9wb2xsc19wZXJfcmVxdWVzdBgPIAEoARIg",
+ "ChhzZXJ2ZXJfcG9sbHNfcGVyX3JlcXVlc3QYECABKAESIgoac2VydmVyX3F1",
+ "ZXJpZXNfcGVyX2NwdV9zZWMYESABKAESIgoaY2xpZW50X3F1ZXJpZXNfcGVy",
+ "X2NwdV9zZWMYEiABKAEigwMKDlNjZW5hcmlvUmVzdWx0EigKCHNjZW5hcmlv",
+ "GAEgASgLMhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxhdGVuY2llcxgC",
+ "IAEoCzIbLmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8KDGNsaWVudF9z",
+ "dGF0cxgDIAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cxIvCgxzZXJ2",
+ "ZXJfc3RhdHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSFAoM",
+ "c2VydmVyX2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsyIy5ncnBjLnRl",
+ "c3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVudF9zdWNjZXNz",
+ "GAcgAygIEhYKDnNlcnZlcl9zdWNjZXNzGAggAygIEjkKD3JlcXVlc3RfcmVz",
+ "dWx0cxgJIAMoCzIgLmdycGMudGVzdGluZy5SZXF1ZXN0UmVzdWx0Q291bnQq",
+ "VgoKQ2xpZW50VHlwZRIPCgtTWU5DX0NMSUVOVBAAEhAKDEFTWU5DX0NMSUVO",
+ "VBABEhAKDE9USEVSX0NMSUVOVBACEhMKD0NBTExCQUNLX0NMSUVOVBADKlsK",
+ "ClNlcnZlclR5cGUSDwoLU1lOQ19TRVJWRVIQABIQCgxBU1lOQ19TRVJWRVIQ",
+ "ARIYChRBU1lOQ19HRU5FUklDX1NFUlZFUhACEhAKDE9USEVSX1NFUlZFUhAD",
+ "KnIKB1JwY1R5cGUSCQoFVU5BUlkQABINCglTVFJFQU1JTkcQARIZChVTVFJF",
+ "QU1JTkdfRlJPTV9DTElFTlQQAhIZChVTVFJFQU1JTkdfRlJPTV9TRVJWRVIQ",
+ "AxIXChNTVFJFQU1JTkdfQk9USF9XQVlTEARiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] {
@@ -109,7 +110,7 @@ namespace Grpc.Testing {
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadParams), global::Grpc.Testing.LoadParams.Parser, new[]{ "ClosedLoop", "Poisson" }, new[]{ "Load" }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SecurityParams), global::Grpc.Testing.SecurityParams.Parser, new[]{ "UseTestCa", "ServerHostOverride", "CredType" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ChannelArg), global::Grpc.Testing.ChannelArg.Parser, new[]{ "Name", "StrValue", "IntValue" }, new[]{ "Value" }, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream", "UseCoalesceApi" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream", "UseCoalesceApi", "MedianLatencyCollectionIntervalMillis" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
@@ -140,6 +141,7 @@ namespace Grpc.Testing {
/// used for some language-specific variants
/// </summary>
[pbr::OriginalName("OTHER_CLIENT")] OtherClient = 2,
+ [pbr::OriginalName("CALLBACK_CLIENT")] CallbackClient = 3,
}
public enum ServerType {
@@ -1054,6 +1056,7 @@ namespace Grpc.Testing {
threadsPerCq_ = other.threadsPerCq_;
messagesPerStream_ = other.messagesPerStream_;
useCoalesceApi_ = other.useCoalesceApi_;
+ medianLatencyCollectionIntervalMillis_ = other.medianLatencyCollectionIntervalMillis_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -1278,6 +1281,21 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "median_latency_collection_interval_millis" field.</summary>
+ public const int MedianLatencyCollectionIntervalMillisFieldNumber = 20;
+ private int medianLatencyCollectionIntervalMillis_;
+ /// <summary>
+ /// If 0, disabled. Else, specifies the period between gathering latency
+ /// medians in milliseconds.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int MedianLatencyCollectionIntervalMillis {
+ get { return medianLatencyCollectionIntervalMillis_; }
+ set {
+ medianLatencyCollectionIntervalMillis_ = value;
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ClientConfig);
@@ -1308,6 +1326,7 @@ namespace Grpc.Testing {
if (ThreadsPerCq != other.ThreadsPerCq) return false;
if (MessagesPerStream != other.MessagesPerStream) return false;
if (UseCoalesceApi != other.UseCoalesceApi) return false;
+ if (MedianLatencyCollectionIntervalMillis != other.MedianLatencyCollectionIntervalMillis) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -1331,6 +1350,7 @@ namespace Grpc.Testing {
if (ThreadsPerCq != 0) hash ^= ThreadsPerCq.GetHashCode();
if (MessagesPerStream != 0) hash ^= MessagesPerStream.GetHashCode();
if (UseCoalesceApi != false) hash ^= UseCoalesceApi.GetHashCode();
+ if (MedianLatencyCollectionIntervalMillis != 0) hash ^= MedianLatencyCollectionIntervalMillis.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -1403,6 +1423,10 @@ namespace Grpc.Testing {
output.WriteRawTag(152, 1);
output.WriteBool(UseCoalesceApi);
}
+ if (MedianLatencyCollectionIntervalMillis != 0) {
+ output.WriteRawTag(160, 1);
+ output.WriteInt32(MedianLatencyCollectionIntervalMillis);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -1456,6 +1480,9 @@ namespace Grpc.Testing {
if (UseCoalesceApi != false) {
size += 2 + 1;
}
+ if (MedianLatencyCollectionIntervalMillis != 0) {
+ size += 2 + pb::CodedOutputStream.ComputeInt32Size(MedianLatencyCollectionIntervalMillis);
+ }
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -1524,6 +1551,9 @@ namespace Grpc.Testing {
if (other.UseCoalesceApi != false) {
UseCoalesceApi = other.UseCoalesceApi;
}
+ if (other.MedianLatencyCollectionIntervalMillis != 0) {
+ MedianLatencyCollectionIntervalMillis = other.MedianLatencyCollectionIntervalMillis;
+ }
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1616,6 +1646,10 @@ namespace Grpc.Testing {
UseCoalesceApi = input.ReadBool();
break;
}
+ case 160: {
+ MedianLatencyCollectionIntervalMillis = input.ReadInt32();
+ break;
+ }
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/EmptyServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/EmptyServiceGrpc.cs
index 2d233fbdc0..7e77f8d114 100644
--- a/src/csharp/Grpc.IntegrationTesting/EmptyServiceGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/EmptyServiceGrpc.cs
@@ -80,6 +80,14 @@ namespace Grpc.Testing {
return grpc::ServerServiceDefinition.CreateBuilder().Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, EmptyServiceBase serviceImpl)
+ {
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 8daf3fa98b..c342f8a107 100755
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.IntegrationTesting</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.IntegrationTesting</PackageId>
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index 9f16f41ac1..c66a9a9161 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -193,6 +193,16 @@ namespace Grpc.Testing {
.AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, MetricsServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges);
+ serviceBinder.AddMethod(__Method_GetGauge, serviceImpl.GetGauge);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
index 9d24762e0a..4135186275 100644
--- a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
+++ b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
@@ -34,11 +34,7 @@ namespace Grpc.IntegrationTesting
{
// Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
GrpcEnvironment.SetLogger(new ConsoleLogger());
-#if NETCOREAPP1_0
- return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
-#else
- return new AutoRun().Execute(args);
-#endif
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs
index 1da0548cb4..954c172272 100644
--- a/src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs
@@ -143,6 +143,15 @@ namespace Grpc.Testing {
.AddMethod(__Method_ReportScenario, serviceImpl.ReportScenario).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, ReportQpsScenarioServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_ReportScenario, serviceImpl.ReportScenario);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 2176916b43..d125fd5627 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -539,6 +539,22 @@ namespace Grpc.Testing {
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, TestServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall);
+ serviceBinder.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall);
+ serviceBinder.AddMethod(__Method_CacheableUnaryCall, serviceImpl.CacheableUnaryCall);
+ serviceBinder.AddMethod(__Method_StreamingOutputCall, serviceImpl.StreamingOutputCall);
+ serviceBinder.AddMethod(__Method_StreamingInputCall, serviceImpl.StreamingInputCall);
+ serviceBinder.AddMethod(__Method_FullDuplexCall, serviceImpl.FullDuplexCall);
+ serviceBinder.AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall);
+ serviceBinder.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall);
+ }
+
}
/// <summary>
/// A simple service NOT implemented at servers so clients can test for
@@ -661,6 +677,15 @@ namespace Grpc.Testing {
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, UnimplementedServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall);
+ }
+
}
/// <summary>
/// A service used to control reconnect server.
@@ -779,6 +804,16 @@ namespace Grpc.Testing {
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, ReconnectServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_Start, serviceImpl.Start);
+ serviceBinder.AddMethod(__Method_Stop, serviceImpl.Stop);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs
index b9e8f91231..5b22337d53 100644
--- a/src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs
@@ -321,6 +321,18 @@ namespace Grpc.Testing {
.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, WorkerServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_RunServer, serviceImpl.RunServer);
+ serviceBinder.AddMethod(__Method_RunClient, serviceImpl.RunClient);
+ serviceBinder.AddMethod(__Method_CoreCount, serviceImpl.CoreCount);
+ serviceBinder.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
index d39d46cf1b..5b1656080a 100644
--- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
+++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Microbenchmarks</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Microbenchmarks</PackageId>
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
index 0c12f38f25..8b586c6ecb 100755
--- a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
@@ -4,7 +4,7 @@
<Import Project="..\Grpc.Core\Common.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<AssemblyName>Grpc.Reflection.Tests</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Grpc.Reflection.Tests</PackageId>
diff --git a/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs b/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs
index 49ed1cc8d4..de4b4af6cf 100644
--- a/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs
@@ -34,11 +34,7 @@ namespace Grpc.Reflection.Tests
{
// Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
GrpcEnvironment.SetLogger(new ConsoleLogger());
-#if NETCOREAPP1_0
- return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
-#else
- return new AutoRun().Execute(args);
-#endif
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
}
}
}
diff --git a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
index c00075b7c6..ed55c2f584 100644
--- a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
+++ b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
@@ -123,6 +123,15 @@ namespace Grpc.Reflection.V1Alpha {
.AddMethod(__Method_ServerReflectionInfo, serviceImpl.ServerReflectionInfo).Build();
}
+ /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+ /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+ /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, ServerReflectionBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_ServerReflectionInfo, serviceImpl.ServerReflectionInfo);
+ }
+
}
}
#endregion
diff --git a/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
index a2d4874eec..cfb40f44ae 100644
--- a/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
+++ b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
@@ -3,7 +3,7 @@
<Import Project="..\Grpc.Core\Version.csproj.include" />
<PropertyGroup>
- <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>net45;netcoreapp1.1</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>
diff --git a/src/csharp/Grpc.Tools.Tests/NUnitMain.cs b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
index 418c33820e..d30d608aa3 100644
--- a/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
@@ -24,10 +24,6 @@ namespace Grpc.Tools.Tests
static class NUnitMain
{
public static int Main(string[] args) =>
-#if NETCOREAPP1_0 || NETCOREAPP1_1
new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
-#else
- new AutoRun().Execute(args);
-#endif
};
}
diff --git a/src/csharp/README.md b/src/csharp/README.md
index d8aed94988..9a91035d06 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -87,6 +87,7 @@ $ python tools/run_tests/run_tests.py -l csharp -c dbg
DOCUMENTATION
-------------
+- [.NET Build Integration](BUILD-INTEGRATION.md)
- [API Reference][]
- [Helloworld Example][]
- [RouteGuide Tutorial][]
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 27688360e9..76d4f14390 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.17.0-dev
+set VERSION=1.18.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat
index dd74de0491..3334d24c11 100644
--- a/src/csharp/build_unitypackage.bat
+++ b/src/csharp/build_unitypackage.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.17.0-dev
+set VERSION=1.18.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/doc/integration.md-fig.1-classic.png b/src/csharp/doc/integration.md-fig.1-classic.png
new file mode 100644
index 0000000000..80c57261ad
--- /dev/null
+++ b/src/csharp/doc/integration.md-fig.1-classic.png
Binary files differ
diff --git a/src/csharp/doc/integration.md-fig.2-sdk.png b/src/csharp/doc/integration.md-fig.2-sdk.png
new file mode 100644
index 0000000000..6d653e4a58
--- /dev/null
+++ b/src/csharp/doc/integration.md-fig.2-sdk.png
Binary files differ
diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
index a95a120d21..55ca6048bc 100644
--- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
+++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
- v = '1.17.0-dev'
+ v = '1.18.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index d5463c0b4c..0be0e3c9a0 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -22,4 +22,4 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.18.0-dev"
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index ca27c03b3c..f2fd692070 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -22,5 +22,5 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.18.0-dev"
#define GRPC_C_VERSION_STRING @"7.0.0-dev"
diff --git a/src/php/composer.json b/src/php/composer.json
index d54db91b5f..9c298c0e85 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Developement use only",
"license": "Apache-2.0",
- "version": "1.17.0",
+ "version": "1.18.0",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index b17f3d9a61..c06bdea7fe 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -393,6 +393,8 @@ PHP_METHOD(Channel, __construct) {
channel->wrapper->target = strdup(target);
channel->wrapper->args_hashstr = strdup(sha1str);
channel->wrapper->creds_hashstr = NULL;
+ channel->wrapper->creds = creds;
+ channel->wrapper->args = args;
if (creds != NULL && creds->hashstr != NULL) {
php_grpc_int creds_hashstr_len = strlen(creds->hashstr);
char *channel_creds_hashstr = malloc(creds_hashstr_len + 1);
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index 27752c9a3f..ce17c4a58a 100644
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -19,6 +19,7 @@
#ifndef NET_GRPC_PHP_GRPC_CHANNEL_H_
#define NET_GRPC_PHP_GRPC_CHANNEL_H_
+#include "channel_credentials.h"
#include "php_grpc.h"
/* Class entry for the PHP Channel class */
@@ -32,6 +33,8 @@ typedef struct _grpc_channel_wrapper {
char *creds_hashstr;
size_t ref_count;
gpr_mu mu;
+ grpc_channel_args args;
+ wrapped_grpc_channel_credentials *creds;
} grpc_channel_wrapper;
/* Wrapper struct for grpc_channel that can be associated with a PHP object */
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index fa54ebd920..9ec2c7cf04 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -103,7 +103,7 @@ if test "$PHP_COVERAGE" = "yes"; then
AC_MSG_ERROR([ccache must be disabled when --enable-coverage option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
fi
- lcov_version_list="1.5 1.6 1.7 1.9 1.10 1.11"
+ lcov_version_list="1.5 1.6 1.7 1.9 1.10 1.11 1.12 1.13"
AC_CHECK_PROG(LCOV, lcov, lcov)
AC_CHECK_PROG(GENHTML, genhtml, genhtml)
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index fabd98975d..111c6f4867 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -26,6 +26,8 @@
#include "call_credentials.h"
#include "server_credentials.h"
#include "completion_queue.h"
+#include <ext/spl/spl_exceptions.h>
+#include <zend_exceptions.h>
ZEND_DECLARE_MODULE_GLOBALS(grpc)
static PHP_GINIT_FUNCTION(grpc);
@@ -86,6 +88,125 @@ ZEND_GET_MODULE(grpc)
}
*/
/* }}} */
+void create_new_channel(
+ wrapped_grpc_channel *channel,
+ char *target,
+ grpc_channel_args args,
+ wrapped_grpc_channel_credentials *creds) {
+ if (creds == NULL) {
+ channel->wrapper->wrapped = grpc_insecure_channel_create(target, &args,
+ NULL);
+ } else {
+ channel->wrapper->wrapped =
+ grpc_secure_channel_create(creds->wrapped, target, &args, NULL);
+ }
+}
+
+void acquire_persistent_locks() {
+ zval *data;
+ PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
+ php_grpc_zend_resource *rsrc =
+ (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
+ if (rsrc == NULL) {
+ break;
+ }
+ channel_persistent_le_t* le = rsrc->ptr;
+
+ gpr_mu_lock(&le->channel->mu);
+ PHP_GRPC_HASH_FOREACH_END()
+}
+
+void release_persistent_locks() {
+ zval *data;
+ PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
+ php_grpc_zend_resource *rsrc =
+ (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
+ if (rsrc == NULL) {
+ break;
+ }
+ channel_persistent_le_t* le = rsrc->ptr;
+
+ gpr_mu_unlock(&le->channel->mu);
+ PHP_GRPC_HASH_FOREACH_END()
+}
+
+void destroy_grpc_channels() {
+ zval *data;
+ PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
+ php_grpc_zend_resource *rsrc =
+ (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
+ if (rsrc == NULL) {
+ break;
+ }
+ channel_persistent_le_t* le = rsrc->ptr;
+
+ wrapped_grpc_channel wrapped_channel;
+ wrapped_channel.wrapper = le->channel;
+ grpc_channel_wrapper *channel = wrapped_channel.wrapper;
+ grpc_channel_destroy(channel->wrapped);
+ PHP_GRPC_HASH_FOREACH_END()
+}
+
+void restart_channels() {
+ zval *data;
+ PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
+ php_grpc_zend_resource *rsrc =
+ (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
+ if (rsrc == NULL) {
+ break;
+ }
+ channel_persistent_le_t* le = rsrc->ptr;
+
+ wrapped_grpc_channel wrapped_channel;
+ wrapped_channel.wrapper = le->channel;
+ grpc_channel_wrapper *channel = wrapped_channel.wrapper;
+ create_new_channel(&wrapped_channel, channel->target, channel->args,
+ channel->creds);
+ gpr_mu_unlock(&channel->mu);
+ PHP_GRPC_HASH_FOREACH_END()
+}
+
+void prefork() {
+ acquire_persistent_locks();
+}
+
+void postfork_child() {
+ TSRMLS_FETCH();
+
+ // loop through persistant list and destroy all underlying grpc_channel objs
+ destroy_grpc_channels();
+
+ // clear completion queue
+ grpc_php_shutdown_completion_queue(TSRMLS_C);
+
+ // clean-up grpc_core
+ grpc_shutdown();
+ if (grpc_is_initialized() > 0) {
+ zend_throw_exception(spl_ce_UnexpectedValueException,
+ "Oops, failed to shutdown gRPC Core after fork()",
+ 1 TSRMLS_CC);
+ }
+
+ // restart grpc_core
+ grpc_init();
+ grpc_php_init_completion_queue(TSRMLS_C);
+
+ // re-create grpc_channel and point wrapped to it
+ // unlock wrapped grpc channel mutex
+ restart_channels();
+}
+
+void postfork_parent() {
+ release_persistent_locks();
+}
+
+void register_fork_handlers() {
+ if (getenv("GRPC_ENABLE_FORK_SUPPORT")) {
+#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
+ pthread_atfork(&prefork, &postfork_parent, &postfork_child);
+#endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
+ }
+}
/* {{{ PHP_MINIT_FUNCTION
*/
@@ -265,6 +386,7 @@ PHP_MINFO_FUNCTION(grpc) {
PHP_RINIT_FUNCTION(grpc) {
if (!GRPC_G(initialized)) {
grpc_init();
+ register_fork_handlers();
grpc_php_init_completion_queue(TSRMLS_C);
GRPC_G(initialized) = 1;
}
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index 70f8bbbf40..1ddf90a667 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define PHP_GRPC_VERSION "1.17.0dev"
+#define PHP_GRPC_VERSION "1.18.0dev"
#endif /* VERSION_H */
diff --git a/src/proto/grpc/channelz/BUILD b/src/proto/grpc/channelz/BUILD
index bdb03d5e2d..b6b485e3e8 100644
--- a/src/proto/grpc/channelz/BUILD
+++ b/src/proto/grpc/channelz/BUILD
@@ -24,3 +24,10 @@ grpc_proto_library(
has_services = True,
well_known_protos = True,
)
+
+filegroup(
+ name = "channelz_proto_file",
+ srcs = [
+ "channelz.proto",
+ ],
+)
diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto
index d930dfcfb4..6202e5e817 100644
--- a/src/proto/grpc/channelz/channelz.proto
+++ b/src/proto/grpc/channelz/channelz.proto
@@ -424,6 +424,8 @@ service Channelz {
rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
// Gets all servers that exist in the process.
rpc GetServers(GetServersRequest) returns (GetServersResponse);
+ // Returns a single Server, or else a NOT_FOUND code.
+ rpc GetServer(GetServerRequest) returns (GetServerResponse);
// Gets all server sockets that exist in the process.
rpc GetServerSockets(GetServerSocketsRequest) returns (GetServerSocketsResponse);
// Returns a single Channel, or else a NOT_FOUND code.
@@ -466,6 +468,17 @@ message GetServersResponse {
bool end = 2;
}
+message GetServerRequest {
+ // server_id is the identifier of the specific server to get.
+ int64 server_id = 1;
+}
+
+message GetServerResponse {
+ // The Server that corresponds to the requested server_id. This field
+ // should be set.
+ Server server = 1;
+}
+
message GetServerSocketsRequest {
int64 server_id = 1;
// start_socket_id indicates that only sockets at or above this id should be
diff --git a/src/proto/grpc/health/v1/BUILD b/src/proto/grpc/health/v1/BUILD
index 97642985c9..38a7d992e0 100644
--- a/src/proto/grpc/health/v1/BUILD
+++ b/src/proto/grpc/health/v1/BUILD
@@ -29,4 +29,3 @@ filegroup(
"health.proto",
],
)
-
diff --git a/src/proto/grpc/reflection/v1alpha/BUILD b/src/proto/grpc/reflection/v1alpha/BUILD
index 4605418447..4d919d029e 100644
--- a/src/proto/grpc/reflection/v1alpha/BUILD
+++ b/src/proto/grpc/reflection/v1alpha/BUILD
@@ -22,3 +22,11 @@ grpc_proto_library(
name = "reflection_proto",
srcs = ["reflection.proto"],
)
+
+filegroup(
+ name = "reflection_proto_file",
+ srcs = [
+ "reflection.proto",
+ ],
+)
+
diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD
index 16721ff2ed..9876d5160a 100644
--- a/src/proto/grpc/testing/BUILD
+++ b/src/proto/grpc/testing/BUILD
@@ -15,6 +15,8 @@
licenses(["notice"]) # Apache v2
load("//bazel:grpc_build_system.bzl", "grpc_proto_library", "grpc_package")
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
grpc_package(name = "testing", visibility = "public")
@@ -48,7 +50,8 @@ grpc_proto_library(
grpc_proto_library(
name = "echo_proto",
srcs = ["echo.proto"],
- deps = ["echo_messages_proto"],
+ deps = ["echo_messages_proto",
+ "simple_messages_proto"],
generate_mocks = True,
)
@@ -58,12 +61,30 @@ grpc_proto_library(
has_services = False,
)
+py_proto_library(
+ name = "py_empty_proto",
+ protos = ["empty.proto",],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
grpc_proto_library(
name = "messages_proto",
srcs = ["messages.proto"],
has_services = False,
)
+py_proto_library(
+ name = "py_messages_proto",
+ protos = ["messages.proto",],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
grpc_proto_library(
name = "metrics_proto",
srcs = ["metrics.proto"],
@@ -100,6 +121,12 @@ grpc_proto_library(
)
grpc_proto_library(
+ name = "simple_messages_proto",
+ srcs = ["simple_messages.proto"],
+ has_services = False,
+)
+
+grpc_proto_library(
name = "stats_proto",
srcs = ["stats.proto"],
has_services = False,
@@ -116,3 +143,17 @@ grpc_proto_library(
"messages_proto",
],
)
+
+py_proto_library(
+ name = "py_test_proto",
+ protos = ["test.proto",],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+ proto_deps = [
+ ":py_empty_proto",
+ ":py_messages_proto",
+ ]
+)
+
diff --git a/src/proto/grpc/testing/compiler_test.proto b/src/proto/grpc/testing/compiler_test.proto
index db5ca48331..9fa5590a59 100644
--- a/src/proto/grpc/testing/compiler_test.proto
+++ b/src/proto/grpc/testing/compiler_test.proto
@@ -20,6 +20,9 @@
syntax = "proto3";
// Ignored detached comment
+// The comments in this file are not meant for readability
+// but rather to test to make sure that the code generator
+// properly preserves comments on files, services, and RPCs
// Ignored package leading comment
package grpc.testing;
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 4cfdc2cafb..564d8234b7 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -33,6 +33,7 @@ enum ServerType {
ASYNC_SERVER = 1;
ASYNC_GENERIC_SERVER = 2;
OTHER_SERVER = 3; // used for some language-specific variants
+ CALLBACK_SERVER = 4;
}
enum RpcType {
diff --git a/src/proto/grpc/testing/echo.proto b/src/proto/grpc/testing/echo.proto
index 13e28320fc..977858f6bc 100644
--- a/src/proto/grpc/testing/echo.proto
+++ b/src/proto/grpc/testing/echo.proto
@@ -16,11 +16,15 @@
syntax = "proto3";
import "src/proto/grpc/testing/echo_messages.proto";
+import "src/proto/grpc/testing/simple_messages.proto";
package grpc.testing;
service EchoTestService {
rpc Echo(EchoRequest) returns (EchoResponse);
+ // A service which checks that the initial metadata sent over contains some
+ // expected key value pair
+ rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse);
rpc RequestStream(stream EchoRequest) returns (EchoResponse);
rpc ResponseStream(EchoRequest) returns (stream EchoResponse);
rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
diff --git a/src/proto/grpc/testing/proto2/BUILD.bazel b/src/proto/grpc/testing/proto2/BUILD.bazel
new file mode 100644
index 0000000000..c4c4f004ef
--- /dev/null
+++ b/src/proto/grpc/testing/proto2/BUILD.bazel
@@ -0,0 +1,30 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
+
+package(default_visibility = ["//visibility:public"])
+
+py_proto_library(
+ name = "empty2_proto",
+ protos = [
+ "empty2.proto",
+ ],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
+py_proto_library(
+ name = "empty2_extensions_proto",
+ protos = [
+ "empty2_extensions.proto",
+ ],
+ proto_deps = [
+ ":empty2_proto",
+ ],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
diff --git a/src/proto/grpc/testing/simple_messages.proto b/src/proto/grpc/testing/simple_messages.proto
new file mode 100644
index 0000000000..4b65d18909
--- /dev/null
+++ b/src/proto/grpc/testing/simple_messages.proto
@@ -0,0 +1,24 @@
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+message SimpleRequest {
+}
+
+message SimpleResponse {
+}
diff --git a/src/python/.gitignore b/src/python/.gitignore
index 7b520579a0..41813129bd 100644
--- a/src/python/.gitignore
+++ b/src/python/.gitignore
@@ -1,3 +1,4 @@
gens/
*_pb2.py
*_pb2_grpc.py
+*.egg-info/
diff --git a/src/python/grpcio/_parallel_compile_patch.py b/src/python/grpcio/_parallel_compile_patch.py
new file mode 100644
index 0000000000..4d03ef49ba
--- /dev/null
+++ b/src/python/grpcio/_parallel_compile_patch.py
@@ -0,0 +1,63 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Patches the compile() to allow enable parallel compilation of C/C++.
+
+build_ext has lots of C/C++ files and normally them one by one.
+Enabling parallel build helps a lot.
+"""
+
+import distutils.ccompiler
+import os
+
+try:
+ BUILD_EXT_COMPILER_JOBS = int(
+ os.environ.get('GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS', '1'))
+except ValueError:
+ BUILD_EXT_COMPILER_JOBS = 1
+
+
+# monkey-patch for parallel compilation
+def _parallel_compile(self,
+ sources,
+ output_dir=None,
+ macros=None,
+ include_dirs=None,
+ debug=0,
+ extra_preargs=None,
+ extra_postargs=None,
+ depends=None):
+ # setup the same way as distutils.ccompiler.CCompiler
+ # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564
+ macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
+ output_dir, macros, include_dirs, sources, depends, extra_postargs)
+ cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
+
+ def _compile_single_file(obj):
+ try:
+ src, ext = build[obj]
+ except KeyError:
+ return
+ self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
+
+ # run compilation of individual files in parallel
+ import multiprocessing.pool
+ multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map(
+ _compile_single_file, objects)
+ return objects
+
+
+def monkeypatch_compile_maybe():
+ """Monkeypatching is dumb, but the build speed gain is worth it."""
+ if BUILD_EXT_COMPILER_JOBS > 1:
+ distutils.ccompiler.CCompiler.compile = _parallel_compile
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 0a3097111f..b805f4277b 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -39,36 +39,6 @@ PROTO_STEM = os.path.join(GRPC_STEM, 'src', 'proto')
PROTO_GEN_STEM = os.path.join(GRPC_STEM, 'src', 'python', 'gens')
CYTHON_STEM = os.path.join(PYTHON_STEM, 'grpc', '_cython')
-CONF_PY_ADDENDUM = """
-extensions.append('sphinx.ext.napoleon')
-napoleon_google_docstring = True
-napoleon_numpy_docstring = True
-napoleon_include_special_with_doc = True
-
-html_theme = 'sphinx_rtd_theme'
-copyright = "2016, The gRPC Authors"
-"""
-
-API_GLOSSARY = """
-
-Glossary
-================
-
-.. glossary::
-
- metadatum
- A key-value pair included in the HTTP header. It is a
- 2-tuple where the first entry is the key and the
- second is the value, i.e. (key, value). The metadata key is an ASCII str,
- and must be a valid HTTP header name. The metadata value can be
- either a valid HTTP ASCII str, or bytes. If bytes are provided,
- the key must end with '-bin', i.e.
- ``('binary-metadata-bin', b'\\x00\\xFF')``
-
- metadata
- A sequence of metadatum.
-"""
-
class CommandError(Exception):
"""Simple exception class for GRPC custom commands."""
@@ -124,25 +94,14 @@ class SphinxDocumentation(setuptools.Command):
def run(self):
# We import here to ensure that setup.py has had a chance to install the
# relevant package eggs first.
- import sphinx
- import sphinx.apidoc
- metadata = self.distribution.metadata
- src_dir = os.path.join(PYTHON_STEM, 'grpc')
- sys.path.append(src_dir)
- sphinx.apidoc.main([
- '', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
- '-V', metadata.version, '-R', metadata.version, '-o',
- os.path.join('doc', 'src'), src_dir
- ])
- conf_filepath = os.path.join('doc', 'src', 'conf.py')
- with open(conf_filepath, 'a') as conf_file:
- conf_file.write(CONF_PY_ADDENDUM)
- glossary_filepath = os.path.join('doc', 'src', 'grpc.rst')
- with open(glossary_filepath, 'a') as glossary_filepath:
- glossary_filepath.write(API_GLOSSARY)
- sphinx.main(
- ['', os.path.join('doc', 'src'),
- os.path.join('doc', 'build')])
+ import sphinx.cmd.build
+ source_dir = os.path.join(GRPC_STEM, 'doc', 'python', 'sphinx')
+ target_dir = os.path.join(GRPC_STEM, 'doc', 'build')
+ exit_code = sphinx.cmd.build.build_main(
+ ['-b', 'html', '-W', '--keep-going', source_dir, target_dir])
+ if exit_code is not 0:
+ raise CommandError(
+ "Documentation generation has warnings or errors")
class BuildProjectMetadata(setuptools.Command):
@@ -253,6 +212,12 @@ class BuildExt(build_ext.build_ext):
LINK_OPTIONS = {}
def build_extensions(self):
+ # This special conditioning is here due to difference of compiler
+ # behavior in gcc and clang. The clang doesn't take --stdc++11
+ # flags but gcc does. Since the setuptools of Python only support
+ # all C or all C++ compilation, the mix of C and C++ will crash.
+ # *By default*, the macOS use clang and Linux use gcc, that's why
+ # the special condition here is checking platform.
if "darwin" in sys.platform:
config = os.environ.get('CONFIG', 'opt')
target_path = os.path.abspath(
@@ -274,8 +239,14 @@ class BuildExt(build_ext.build_ext):
extra_defines = [
'EXTRA_DEFINES="GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1"'
]
+ # Ensure the BoringSSL are built instead of using system provided
+ # libraries. It prevents dependency issues while distributing to
+ # Mac users who use MacPorts to manage their libraries. #17002
+ mod_env = dict(os.environ)
+ mod_env['REQUIRE_CUSTOM_LIBRARIES_opt'] = '1'
make_process = subprocess.Popen(
['make'] + extra_defines + targets,
+ env=mod_env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
make_out, make_err = make_process.communicate()
diff --git a/src/python/grpcio/grpc/BUILD.bazel b/src/python/grpcio/grpc/BUILD.bazel
index 2e6839ef2d..6958ccdfb6 100644
--- a/src/python/grpcio/grpc/BUILD.bazel
+++ b/src/python/grpcio/grpc/BUILD.bazel
@@ -13,7 +13,6 @@ py_library(
":interceptor",
":server",
"//src/python/grpcio/grpc/_cython:cygrpc",
- "//src/python/grpcio/grpc/beta",
"//src/python/grpcio/grpc/experimental",
"//src/python/grpcio/grpc/framework",
requirement('enum34'),
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 863696d236..6022fc3ef2 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -15,12 +15,14 @@
import abc
import enum
+import logging
import sys
-
import six
from grpc._cython import cygrpc as _cygrpc
+logging.getLogger(__name__).addHandler(logging.NullHandler())
+
############################## Future Interface ###############################
@@ -48,11 +50,13 @@ class Future(six.with_metaclass(abc.ABCMeta)):
Returns:
bool:
Returns True if the computation was canceled.
+
Returns False under all other circumstances, for example:
+
1. computation has begun and could not be canceled.
2. computation has finished
3. computation is scheduled for execution and it is impossible
- to determine its state without blocking.
+ to determine its state without blocking.
"""
raise NotImplementedError()
@@ -66,7 +70,9 @@ class Future(six.with_metaclass(abc.ABCMeta)):
bool:
Returns True if the computation was cancelled before its result became
available.
- False under all other circumstances, for example:
+
+ Returns False under all other circumstances, for example:
+
1. computation was not cancelled.
2. computation's result is available.
"""
@@ -79,9 +85,9 @@ class Future(six.with_metaclass(abc.ABCMeta)):
This method does not block.
Returns:
- bool:
Returns True if the computation is scheduled for execution or
currently executing.
+
Returns False if the computation already executed or was cancelled.
"""
raise NotImplementedError()
@@ -210,7 +216,33 @@ class ChannelConnectivity(enum.Enum):
@enum.unique
class StatusCode(enum.Enum):
- """Mirrors grpc_status_code in the gRPC Core."""
+ """Mirrors grpc_status_code in the gRPC Core.
+
+ Attributes:
+ OK: Not an error; returned on success
+ CANCELLED: The operation was cancelled (typically by the caller).
+ UNKNOWN: Unknown error.
+ INVALID_ARGUMENT: Client specified an invalid argument.
+ DEADLINE_EXCEEDED: Deadline expired before operation could complete.
+ NOT_FOUND: Some requested entity (e.g., file or directory) was not found.
+ ALREADY_EXISTS: Some entity that we attempted to create (e.g., file or directory)
+ already exists.
+ PERMISSION_DENIED: The caller does not have permission to execute the specified
+ operation.
+ UNAUTHENTICATED: The request does not have valid authentication credentials for the
+ operation.
+ RESOURCE_EXHAUSTED: Some resource has been exhausted, perhaps a per-user quota, or
+ perhaps the entire file system is out of space.
+ FAILED_PRECONDITION: Operation was rejected because the system is not in a state
+ required for the operation's execution.
+ ABORTED: The operation was aborted, typically due to a concurrency issue
+ like sequencer check failures, transaction aborts, etc.
+ UNIMPLEMENTED: Operation is not implemented or not supported/enabled in this service.
+ INTERNAL: Internal errors. Means some invariants expected by underlying
+ system has been broken.
+ UNAVAILABLE: The service is currently unavailable.
+ DATA_LOSS: Unrecoverable data loss or corruption.
+ """
OK = (_cygrpc.StatusCode.ok, 'ok')
CANCELLED = (_cygrpc.StatusCode.cancelled, 'cancelled')
UNKNOWN = (_cygrpc.StatusCode.unknown, 'unknown')
@@ -357,6 +389,8 @@ class ClientCallDetails(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to
the service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional flag t
+ enable wait for ready mechanism.
"""
@@ -450,8 +484,7 @@ class StreamUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
actual RPC on the underlying Channel. It is the interceptor's
responsibility to call it if it decides to move the RPC forward.
The interceptor can use
- `response_future = continuation(client_call_details,
- request_iterator)`
+ `response_future = continuation(client_call_details, request_iterator)`
to continue with the RPC. `continuation` returns an object that is
both a Call for the RPC and a Future. In the event of RPC completion,
the return Call-Future's result value will be the response message
@@ -462,11 +495,11 @@ class StreamUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator: An iterator that yields request values for the RPC.
Returns:
- An object that is both a Call for the RPC and a Future.
- In the event of RPC completion, the return Call-Future's
- result value will be the response message of the RPC.
- Should the event terminate with non-OK status, the returned
- Call-Future's exception value will be an RpcError.
+ An object that is both a Call for the RPC and a Future.
+ In the event of RPC completion, the return Call-Future's
+ result value will be the response message of the RPC.
+ Should the event terminate with non-OK status, the returned
+ Call-Future's exception value will be an RpcError.
"""
raise NotImplementedError()
@@ -482,13 +515,13 @@ class StreamStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator):
"""Intercepts a stream-stream invocation.
+ Args:
continuation: A function that proceeds with the invocation by
executing the next interceptor in chain or invoking the
actual RPC on the underlying Channel. It is the interceptor's
responsibility to call it if it decides to move the RPC forward.
The interceptor can use
- `response_iterator = continuation(client_call_details,
- request_iterator)`
+ `response_iterator = continuation(client_call_details, request_iterator)`
to continue with the RPC. `continuation` returns an object that is
both a Call for the RPC and an iterator for response values.
Drawing response values from the returned Call-iterator may
@@ -499,10 +532,10 @@ class StreamStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator: An iterator that yields request values for the RPC.
Returns:
- An object that is both a Call for the RPC and an iterator of
- response values. Drawing response values from the returned
- Call-iterator may raise RpcError indicating termination of
- the RPC with non-OK status.
+ An object that is both a Call for the RPC and an iterator of
+ response values. Drawing response values from the returned
+ Call-iterator may raise RpcError indicating termination of
+ the RPC with non-OK status.
"""
raise NotImplementedError()
@@ -609,7 +642,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-unary RPC from client-side."""
@abc.abstractmethod
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -619,6 +657,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC.
@@ -631,7 +671,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -641,6 +686,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC and a Call value for the RPC.
@@ -653,7 +700,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
- def future(self, request, timeout=None, metadata=None, credentials=None):
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -663,6 +715,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and a Future.
@@ -678,7 +732,12 @@ class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-stream RPC from client-side."""
@abc.abstractmethod
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Invokes the underlying RPC.
Args:
@@ -688,6 +747,8 @@ class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: An optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and an iterator of
@@ -706,7 +767,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -717,6 +779,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC.
@@ -733,7 +797,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC on the client.
Args:
@@ -744,6 +809,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC and a Call object for the RPC.
@@ -760,7 +827,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Asynchronously invokes the underlying RPC on the client.
Args:
@@ -770,6 +838,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and a Future.
@@ -789,7 +859,8 @@ class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Invokes the underlying RPC on the client.
Args:
@@ -799,6 +870,8 @@ class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and an iterator of
@@ -972,8 +1045,7 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
"""Gets one or more peer identity(s).
Equivalent to
- servicer_context.auth_context().get(
- servicer_context.peer_identity_key())
+ servicer_context.auth_context().get(servicer_context.peer_identity_key())
Returns:
An iterable of the identities, or None if the call is not
@@ -1651,7 +1723,7 @@ def server(thread_pool,
handlers. The interceptors are given control in the order they are
specified. This is an EXPERIMENTAL API.
options: An optional list of key-value pairs (channel args in gRPC runtime)
- to configure the channel.
+ to configure the channel.
maximum_concurrent_rpcs: The maximum number of concurrent RPCs this server
will service before returning RESOURCE_EXHAUSTED status, or None to
indicate no limit.
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index eeeb4ddb33..35fa82d56b 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -24,7 +24,6 @@ from grpc import _grpcio_metadata
from grpc._cython import cygrpc
from grpc.framework.foundation import callable_util
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
_USER_AGENT = 'grpc-python/{}'.format(_grpcio_metadata.__version__)
@@ -176,6 +175,7 @@ def _event_handler(state, response_deserializer):
return handle_event
+#pylint: disable=too-many-statements
def _consume_request_iterator(request_iterator, state, call, request_serializer,
event_handler):
if cygrpc.is_fork_support_enabled():
@@ -467,10 +467,11 @@ def _end_unary_response_blocking(state, call, with_call, deadline):
raise _Rendezvous(state, None, None, deadline)
-def _stream_unary_invocation_operationses(metadata):
+def _stream_unary_invocation_operationses(metadata, initial_metadata_flags):
return (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
),
@@ -478,15 +479,19 @@ def _stream_unary_invocation_operationses(metadata):
)
-def _stream_unary_invocation_operationses_and_tags(metadata):
+def _stream_unary_invocation_operationses_and_tags(metadata,
+ initial_metadata_flags):
return tuple((
operations,
None,
- ) for operations in _stream_unary_invocation_operationses(metadata))
+ )
+ for operations in _stream_unary_invocation_operationses(
+ metadata, initial_metadata_flags))
class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -495,15 +500,18 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def _prepare(self, request, timeout, metadata):
+ def _prepare(self, request, timeout, metadata, wait_for_ready):
deadline, serialized_request, rendezvous = _start_unary_request(
request, timeout, self._request_serializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
if serialized_request is None:
return None, None, None, rendezvous
else:
state = _RPCState(_UNARY_UNARY_INITIAL_DUE, None, None, None, None)
operations = (
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.SendMessageOperation(serialized_request, _EMPTY_FLAGS),
cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
@@ -512,9 +520,10 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
)
return state, operations, deadline, None
- def _blocking(self, request, timeout, metadata, credentials):
+ def _blocking(self, request, timeout, metadata, credentials,
+ wait_for_ready):
state, operations, deadline, rendezvous = self._prepare(
- request, timeout, metadata)
+ request, timeout, metadata, wait_for_ready)
if state is None:
raise rendezvous
else:
@@ -528,17 +537,34 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
_handle_event(event, state, self._response_deserializer)
return state, call,
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
- state, call, = self._blocking(request, timeout, metadata, credentials)
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ state, call, = self._blocking(request, timeout, metadata, credentials,
+ wait_for_ready)
return _end_unary_response_blocking(state, call, False, None)
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
- state, call, = self._blocking(request, timeout, metadata, credentials)
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ state, call, = self._blocking(request, timeout, metadata, credentials,
+ wait_for_ready)
return _end_unary_response_blocking(state, call, True, None)
- def future(self, request, timeout=None, metadata=None, credentials=None):
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
state, operations, deadline, rendezvous = self._prepare(
- request, timeout, metadata)
+ request, timeout, metadata, wait_for_ready)
if state is None:
raise rendezvous
else:
@@ -553,6 +579,7 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -561,16 +588,24 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
deadline, serialized_request, rendezvous = _start_unary_request(
request, timeout, self._request_serializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
if serialized_request is None:
raise rendezvous
else:
state = _RPCState(_UNARY_STREAM_INITIAL_DUE, None, None, None, None)
operationses = (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.SendMessageOperation(serialized_request,
_EMPTY_FLAGS),
cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
@@ -589,6 +624,7 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -597,13 +633,17 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def _blocking(self, request_iterator, timeout, metadata, credentials):
+ def _blocking(self, request_iterator, timeout, metadata, credentials,
+ wait_for_ready):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
call = self._channel.segregated_call(
0, self._method, None, deadline, metadata, None
if credentials is None else credentials._credentials,
- _stream_unary_invocation_operationses_and_tags(metadata))
+ _stream_unary_invocation_operationses_and_tags(
+ metadata, initial_metadata_flags))
_consume_request_iterator(request_iterator, state, call,
self._request_serializer, None)
while True:
@@ -619,32 +659,38 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
state, call, = self._blocking(request_iterator, timeout, metadata,
- credentials)
+ credentials, wait_for_ready)
return _end_unary_response_blocking(state, call, False, None)
def with_call(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
state, call, = self._blocking(request_iterator, timeout, metadata,
- credentials)
+ credentials, wait_for_ready)
return _end_unary_response_blocking(state, call, True, None)
def future(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
event_handler = _event_handler(state, self._response_deserializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
call = self._managed_call(
0, self._method, None, deadline, metadata, None
if credentials is None else credentials._credentials,
- _stream_unary_invocation_operationses(metadata), event_handler)
+ _stream_unary_invocation_operationses(
+ metadata, initial_metadata_flags), event_handler)
_consume_request_iterator(request_iterator, state, call,
self._request_serializer, event_handler)
return _Rendezvous(state, call, self._response_deserializer, deadline)
@@ -652,6 +698,7 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -664,12 +711,16 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_STREAM_INITIAL_DUE, None, None, None, None)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
operationses = (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
),
(cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),),
@@ -684,6 +735,24 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
return _Rendezvous(state, call, self._response_deserializer, deadline)
+class _InitialMetadataFlags(int):
+ """Stores immutable initial metadata flags"""
+
+ def __new__(cls, value=_EMPTY_FLAGS):
+ value &= cygrpc.InitialMetadataFlags.used_mask
+ return super(_InitialMetadataFlags, cls).__new__(cls, value)
+
+ def with_wait_for_ready(self, wait_for_ready):
+ if wait_for_ready is not None:
+ if wait_for_ready:
+ self = self.__class__(self | cygrpc.InitialMetadataFlags.wait_for_ready | \
+ cygrpc.InitialMetadataFlags.wait_for_ready_explicitly_set)
+ elif not wait_for_ready:
+ self = self.__class__(self & ~cygrpc.InitialMetadataFlags.wait_for_ready | \
+ cygrpc.InitialMetadataFlags.wait_for_ready_explicitly_set)
+ return self
+
+
class _ChannelCallState(object):
def __init__(self, channel):
@@ -980,8 +1049,9 @@ class Channel(grpc.Channel):
# for as long as they are in use and to close them after using them,
# then deletion of this grpc._channel.Channel instance can be made to
# effect closure of the underlying cygrpc.Channel instance.
- cygrpc.fork_unregister_channel(self)
+ if cygrpc is not None: # Globals may have already been collected.
+ cygrpc.fork_unregister_channel(self)
# This prevent the failed-at-initializing object removal from failing.
# Though the __init__ failed, the removal will still trigger __del__.
- if hasattr(self, "_connectivity_state"):
+ if _moot is not None and hasattr(self, "_connectivity_state"):
_moot(self._connectivity_state)
diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py
index 3805c7e82a..f69127e38e 100644
--- a/src/python/grpcio/grpc/_common.py
+++ b/src/python/grpcio/grpc/_common.py
@@ -20,7 +20,6 @@ import six
import grpc
from grpc._cython import cygrpc
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
@@ -66,18 +65,13 @@ def encode(s):
if isinstance(s, bytes):
return s
else:
- return s.encode('ascii')
+ return s.encode('utf8')
def decode(b):
- if isinstance(b, str):
- return b
- else:
- try:
- return b.decode('utf8')
- except UnicodeDecodeError:
- _LOGGER.exception('Invalid encoding on %s', b)
- return b.decode('latin1')
+ if isinstance(b, bytes):
+ return b.decode('utf-8', 'replace')
+ return b
def _transform(message, transformer, exception_message):
diff --git a/src/python/grpcio/grpc/_cython/BUILD.bazel b/src/python/grpcio/grpc/_cython/BUILD.bazel
index cfd3a51d9b..e318298d0a 100644
--- a/src/python/grpcio/grpc/_cython/BUILD.bazel
+++ b/src/python/grpcio/grpc/_cython/BUILD.bazel
@@ -12,6 +12,7 @@ pyx_library(
"_cygrpc/grpc_string.pyx.pxi",
"_cygrpc/arguments.pyx.pxi",
"_cygrpc/call.pyx.pxi",
+ "_cygrpc/channelz.pyx.pxi",
"_cygrpc/channel.pyx.pxi",
"_cygrpc/credentials.pyx.pxi",
"_cygrpc/completion_queue.pyx.pxi",
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi
new file mode 100644
index 0000000000..113f7976dd
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi
@@ -0,0 +1,69 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def channelz_get_top_channels(start_channel_id):
+ cdef char *c_returned_str = grpc_channelz_get_top_channels(
+ start_channel_id,
+ )
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get top channels, please ensure your' \
+ ' start_channel_id==%s is valid' % start_channel_id)
+ return c_returned_str
+
+def channelz_get_servers(start_server_id):
+ cdef char *c_returned_str = grpc_channelz_get_servers(start_server_id)
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get servers, please ensure your' \
+ ' start_server_id==%s is valid' % start_server_id)
+ return c_returned_str
+
+def channelz_get_server(server_id):
+ cdef char *c_returned_str = grpc_channelz_get_server(server_id)
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get the server, please ensure your' \
+ ' server_id==%s is valid' % server_id)
+ return c_returned_str
+
+def channelz_get_server_sockets(server_id, start_socket_id):
+ cdef char *c_returned_str = grpc_channelz_get_server_sockets(
+ server_id,
+ start_socket_id,
+ )
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get server sockets, please ensure your' \
+ ' server_id==%s and start_socket_id==%s is valid' %
+ (server_id, start_socket_id))
+ return c_returned_str
+
+def channelz_get_channel(channel_id):
+ cdef char *c_returned_str = grpc_channelz_get_channel(channel_id)
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get the channel, please ensure your' \
+ ' channel_id==%s is valid' % (channel_id))
+ return c_returned_str
+
+def channelz_get_subchannel(subchannel_id):
+ cdef char *c_returned_str = grpc_channelz_get_subchannel(subchannel_id)
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get the subchannel, please ensure your' \
+ ' subchannel_id==%s is valid' % (subchannel_id))
+ return c_returned_str
+
+def channelz_get_socket(socket_id):
+ cdef char *c_returned_str = grpc_channelz_get_socket(socket_id)
+ if c_returned_str == NULL:
+ raise ValueError('Failed to get the socket, please ensure your' \
+ ' socket_id==%s is valid' % (socket_id))
+ return c_returned_str
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
index 8d73215247..1cef726970 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
@@ -15,7 +15,7 @@
cdef class CallCredentials:
- cdef grpc_call_credentials *c(self)
+ cdef grpc_call_credentials *c(self) except *
# TODO(https://github.com/grpc/grpc/issues/12531): remove.
cdef grpc_call_credentials *c_credentials
@@ -36,7 +36,7 @@ cdef class MetadataPluginCallCredentials(CallCredentials):
cdef readonly object _metadata_plugin
cdef readonly bytes _name
- cdef grpc_call_credentials *c(self)
+ cdef grpc_call_credentials *c(self) except *
cdef grpc_call_credentials *_composition(call_credentialses)
@@ -46,12 +46,12 @@ cdef class CompositeCallCredentials(CallCredentials):
cdef readonly tuple _call_credentialses
- cdef grpc_call_credentials *c(self)
+ cdef grpc_call_credentials *c(self) except *
cdef class ChannelCredentials:
- cdef grpc_channel_credentials *c(self)
+ cdef grpc_channel_credentials *c(self) except *
# TODO(https://github.com/grpc/grpc/issues/12531): remove.
cdef grpc_channel_credentials *c_credentials
@@ -68,7 +68,7 @@ cdef class SSLChannelCredentials(ChannelCredentials):
cdef readonly object _private_key
cdef readonly object _certificate_chain
- cdef grpc_channel_credentials *c(self)
+ cdef grpc_channel_credentials *c(self) except *
cdef class CompositeChannelCredentials(ChannelCredentials):
@@ -76,7 +76,7 @@ cdef class CompositeChannelCredentials(ChannelCredentials):
cdef readonly tuple _call_credentialses
cdef readonly ChannelCredentials _channel_credentials
- cdef grpc_channel_credentials *c(self)
+ cdef grpc_channel_credentials *c(self) except *
cdef class ServerCertificateConfig:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 63048e8da0..2f51be40ce 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -35,7 +35,7 @@ def _spawn_callback_async(callback, args):
cdef class CallCredentials:
- cdef grpc_call_credentials *c(self):
+ cdef grpc_call_credentials *c(self) except *:
raise NotImplementedError()
@@ -61,6 +61,7 @@ cdef int _get_metadata(
cdef void _destroy(void *state) with gil:
cpython.Py_DECREF(<object>state)
+ grpc_shutdown()
cdef class MetadataPluginCallCredentials(CallCredentials):
@@ -69,13 +70,14 @@ cdef class MetadataPluginCallCredentials(CallCredentials):
self._metadata_plugin = metadata_plugin
self._name = name
- cdef grpc_call_credentials *c(self):
+ cdef grpc_call_credentials *c(self) except *:
cdef grpc_metadata_credentials_plugin c_metadata_plugin
c_metadata_plugin.get_metadata = _get_metadata
c_metadata_plugin.destroy = _destroy
c_metadata_plugin.state = <void *>self._metadata_plugin
c_metadata_plugin.type = self._name
cpython.Py_INCREF(self._metadata_plugin)
+ fork_handlers_and_grpc_init()
return grpc_metadata_credentials_create_from_plugin(c_metadata_plugin, NULL)
@@ -101,13 +103,13 @@ cdef class CompositeCallCredentials(CallCredentials):
def __cinit__(self, call_credentialses):
self._call_credentialses = call_credentialses
- cdef grpc_call_credentials *c(self):
+ cdef grpc_call_credentials *c(self) except *:
return _composition(self._call_credentialses)
cdef class ChannelCredentials:
- cdef grpc_channel_credentials *c(self):
+ cdef grpc_channel_credentials *c(self) except *:
raise NotImplementedError()
@@ -129,11 +131,13 @@ cdef class SSLSessionCacheLRU:
cdef class SSLChannelCredentials(ChannelCredentials):
def __cinit__(self, pem_root_certificates, private_key, certificate_chain):
+ if pem_root_certificates is not None and not isinstance(pem_root_certificates, bytes):
+ raise TypeError('expected certificate to be bytes, got %s' % (type(pem_root_certificates)))
self._pem_root_certificates = pem_root_certificates
self._private_key = private_key
self._certificate_chain = certificate_chain
- cdef grpc_channel_credentials *c(self):
+ cdef grpc_channel_credentials *c(self) except *:
cdef const char *c_pem_root_certificates
cdef grpc_ssl_pem_key_cert_pair c_pem_key_certificate_pair
if self._pem_root_certificates is None:
@@ -162,7 +166,7 @@ cdef class CompositeChannelCredentials(ChannelCredentials):
self._call_credentialses = call_credentialses
self._channel_credentials = channel_credentials
- cdef grpc_channel_credentials *c(self):
+ cdef grpc_channel_credentials *c(self) except *:
cdef grpc_channel_credentials *c_channel_credentials
c_channel_credentials = self._channel_credentials.c()
cdef grpc_call_credentials *c_call_credentials_composition = _composition(
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 4781219319..5bbc10af25 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -13,6 +13,7 @@
# limitations under the License.
cimport libc.time
+from libc.stdint cimport intptr_t
# Typedef types with approximately the same semantics to provide their names to
@@ -121,7 +122,6 @@ cdef extern from "grpc/grpc.h":
GRPC_STATUS_DATA_LOSS
GRPC_STATUS__DO_NOT_USE
- const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
const char *GRPC_ARG_ENABLE_CENSUS
const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
const char *GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH
@@ -140,6 +140,10 @@ cdef extern from "grpc/grpc.h":
const int GRPC_WRITE_NO_COMPRESS
const int GRPC_WRITE_USED_MASK
+ const int GRPC_INITIAL_METADATA_WAIT_FOR_READY
+ const int GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+ const int GRPC_INITIAL_METADATA_USED_MASK
+
const int GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
ctypedef struct grpc_completion_queue:
@@ -186,12 +190,6 @@ cdef extern from "grpc/grpc.h":
size_t arguments_length "num_args"
grpc_arg *arguments "args"
- ctypedef enum grpc_compression_level:
- GRPC_COMPRESS_LEVEL_NONE
- GRPC_COMPRESS_LEVEL_LOW
- GRPC_COMPRESS_LEVEL_MED
- GRPC_COMPRESS_LEVEL_HIGH
-
ctypedef enum grpc_stream_compression_level:
GRPC_STREAM_COMPRESS_LEVEL_NONE
GRPC_STREAM_COMPRESS_LEVEL_LOW
@@ -387,6 +385,15 @@ cdef extern from "grpc/grpc.h":
void grpc_server_cancel_all_calls(grpc_server *server) nogil
void grpc_server_destroy(grpc_server *server) nogil
+ char* grpc_channelz_get_top_channels(intptr_t start_channel_id)
+ char* grpc_channelz_get_servers(intptr_t start_server_id)
+ char* grpc_channelz_get_server(intptr_t server_id)
+ char* grpc_channelz_get_server_sockets(intptr_t server_id,
+ intptr_t start_socket_id)
+ char* grpc_channelz_get_channel(intptr_t channel_id)
+ char* grpc_channelz_get_subchannel(intptr_t subchannel_id)
+ char* grpc_channelz_get_socket(intptr_t socket_id)
+
cdef extern from "grpc/grpc_security.h":
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
index f9a1b2856d..a1618d04d0 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
@@ -266,7 +266,7 @@ cdef grpc_error* socket_listen(grpc_custom_socket* socket) with gil:
(<SocketWrapper>socket.impl).socket.listen(50)
return grpc_error_none()
-cdef void accept_callback_cython(SocketWrapper s):
+cdef void accept_callback_cython(SocketWrapper s) except *:
try:
conn, address = s.socket.accept()
sw = SocketWrapper()
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
index 334e561baa..00a1b23a67 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
@@ -14,7 +14,6 @@
import logging
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
# This function will ascii encode unicode string inputs if neccesary.
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pxd.pxi
index a18c365807..fc72ac1576 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pxd.pxi
@@ -14,10 +14,10 @@
cdef void _store_c_metadata(
- metadata, grpc_metadata **c_metadata, size_t *c_count)
+ metadata, grpc_metadata **c_metadata, size_t *c_count) except *
-cdef void _release_c_metadata(grpc_metadata *c_metadata, int count)
+cdef void _release_c_metadata(grpc_metadata *c_metadata, int count) except *
cdef tuple _metadatum(grpc_slice key_slice, grpc_slice value_slice)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
index c39fef08fa..caf867b569 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
@@ -15,11 +15,17 @@
import collections
+class InitialMetadataFlags:
+ used_mask = GRPC_INITIAL_METADATA_USED_MASK
+ wait_for_ready = GRPC_INITIAL_METADATA_WAIT_FOR_READY
+ wait_for_ready_explicitly_set = GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+
+
_Metadatum = collections.namedtuple('_Metadatum', ('key', 'value',))
cdef void _store_c_metadata(
- metadata, grpc_metadata **c_metadata, size_t *c_count):
+ metadata, grpc_metadata **c_metadata, size_t *c_count) except *:
if metadata is None:
c_count[0] = 0
c_metadata[0] = NULL
@@ -39,7 +45,7 @@ cdef void _store_c_metadata(
c_metadata[0][index].value = _slice_from_bytes(encoded_value)
-cdef void _release_c_metadata(grpc_metadata *c_metadata, int count):
+cdef void _release_c_metadata(grpc_metadata *c_metadata, int count) except *:
if 0 < count:
for index in range(count):
grpc_slice_unref(c_metadata[index].key)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi
index 69a2a4989e..c9df32dadf 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi
@@ -15,8 +15,8 @@
cdef class Operation:
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
# TODO(https://github.com/grpc/grpc/issues/7950): Eliminate this!
cdef grpc_op c_op
@@ -29,8 +29,8 @@ cdef class SendInitialMetadataOperation(Operation):
cdef grpc_metadata *_c_initial_metadata
cdef size_t _c_initial_metadata_count
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class SendMessageOperation(Operation):
@@ -39,16 +39,16 @@ cdef class SendMessageOperation(Operation):
cdef readonly int _flags
cdef grpc_byte_buffer *_c_message_byte_buffer
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class SendCloseFromClientOperation(Operation):
cdef readonly int _flags
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class SendStatusFromServerOperation(Operation):
@@ -61,8 +61,8 @@ cdef class SendStatusFromServerOperation(Operation):
cdef size_t _c_trailing_metadata_count
cdef grpc_slice _c_details
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class ReceiveInitialMetadataOperation(Operation):
@@ -71,8 +71,8 @@ cdef class ReceiveInitialMetadataOperation(Operation):
cdef tuple _initial_metadata
cdef grpc_metadata_array _c_initial_metadata
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class ReceiveMessageOperation(Operation):
@@ -81,8 +81,8 @@ cdef class ReceiveMessageOperation(Operation):
cdef grpc_byte_buffer *_c_message_byte_buffer
cdef bytes _message
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class ReceiveStatusOnClientOperation(Operation):
@@ -97,8 +97,8 @@ cdef class ReceiveStatusOnClientOperation(Operation):
cdef str _details
cdef str _error_string
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
cdef class ReceiveCloseOnServerOperation(Operation):
@@ -107,5 +107,5 @@ cdef class ReceiveCloseOnServerOperation(Operation):
cdef object _cancelled
cdef int _c_cancelled
- cdef void c(self)
- cdef void un_c(self)
+ cdef void c(self) except *
+ cdef void un_c(self) except *
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi
index 454627f570..c8a390106a 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi
@@ -15,10 +15,10 @@
cdef class Operation:
- cdef void c(self):
+ cdef void c(self) except *:
raise NotImplementedError()
- cdef void un_c(self):
+ cdef void un_c(self) except *:
raise NotImplementedError()
@@ -31,7 +31,7 @@ cdef class SendInitialMetadataOperation(Operation):
def type(self):
return GRPC_OP_SEND_INITIAL_METADATA
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_SEND_INITIAL_METADATA
self.c_op.flags = self._flags
_store_c_metadata(
@@ -41,7 +41,7 @@ cdef class SendInitialMetadataOperation(Operation):
self.c_op.data.send_initial_metadata.count = self._c_initial_metadata_count
self.c_op.data.send_initial_metadata.maybe_compression_level.is_set = 0
- cdef void un_c(self):
+ cdef void un_c(self) except *:
_release_c_metadata(
self._c_initial_metadata, self._c_initial_metadata_count)
@@ -55,7 +55,7 @@ cdef class SendMessageOperation(Operation):
def type(self):
return GRPC_OP_SEND_MESSAGE
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_SEND_MESSAGE
self.c_op.flags = self._flags
cdef grpc_slice message_slice = grpc_slice_from_copied_buffer(
@@ -65,7 +65,7 @@ cdef class SendMessageOperation(Operation):
grpc_slice_unref(message_slice)
self.c_op.data.send_message.send_message = self._c_message_byte_buffer
- cdef void un_c(self):
+ cdef void un_c(self) except *:
grpc_byte_buffer_destroy(self._c_message_byte_buffer)
@@ -77,11 +77,11 @@ cdef class SendCloseFromClientOperation(Operation):
def type(self):
return GRPC_OP_SEND_CLOSE_FROM_CLIENT
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_SEND_CLOSE_FROM_CLIENT
self.c_op.flags = self._flags
- cdef void un_c(self):
+ cdef void un_c(self) except *:
pass
@@ -96,7 +96,7 @@ cdef class SendStatusFromServerOperation(Operation):
def type(self):
return GRPC_OP_SEND_STATUS_FROM_SERVER
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_SEND_STATUS_FROM_SERVER
self.c_op.flags = self._flags
_store_c_metadata(
@@ -110,7 +110,7 @@ cdef class SendStatusFromServerOperation(Operation):
self._c_details = _slice_from_bytes(_encode(self._details))
self.c_op.data.send_status_from_server.status_details = &self._c_details
- cdef void un_c(self):
+ cdef void un_c(self) except *:
grpc_slice_unref(self._c_details)
_release_c_metadata(
self._c_trailing_metadata, self._c_trailing_metadata_count)
@@ -124,14 +124,14 @@ cdef class ReceiveInitialMetadataOperation(Operation):
def type(self):
return GRPC_OP_RECV_INITIAL_METADATA
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_RECV_INITIAL_METADATA
self.c_op.flags = self._flags
grpc_metadata_array_init(&self._c_initial_metadata)
self.c_op.data.receive_initial_metadata.receive_initial_metadata = (
&self._c_initial_metadata)
- cdef void un_c(self):
+ cdef void un_c(self) except *:
self._initial_metadata = _metadata(&self._c_initial_metadata)
grpc_metadata_array_destroy(&self._c_initial_metadata)
@@ -147,13 +147,13 @@ cdef class ReceiveMessageOperation(Operation):
def type(self):
return GRPC_OP_RECV_MESSAGE
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_RECV_MESSAGE
self.c_op.flags = self._flags
self.c_op.data.receive_message.receive_message = (
&self._c_message_byte_buffer)
- cdef void un_c(self):
+ cdef void un_c(self) except *:
cdef grpc_byte_buffer_reader message_reader
cdef bint message_reader_status
cdef grpc_slice message_slice
@@ -189,7 +189,7 @@ cdef class ReceiveStatusOnClientOperation(Operation):
def type(self):
return GRPC_OP_RECV_STATUS_ON_CLIENT
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_RECV_STATUS_ON_CLIENT
self.c_op.flags = self._flags
grpc_metadata_array_init(&self._c_trailing_metadata)
@@ -202,7 +202,7 @@ cdef class ReceiveStatusOnClientOperation(Operation):
self.c_op.data.receive_status_on_client.error_string = (
&self._c_error_string)
- cdef void un_c(self):
+ cdef void un_c(self) except *:
self._trailing_metadata = _metadata(&self._c_trailing_metadata)
grpc_metadata_array_destroy(&self._c_trailing_metadata)
self._code = self._c_code
@@ -235,12 +235,12 @@ cdef class ReceiveCloseOnServerOperation(Operation):
def type(self):
return GRPC_OP_RECV_CLOSE_ON_SERVER
- cdef void c(self):
+ cdef void c(self) except *:
self.c_op.type = GRPC_OP_RECV_CLOSE_ON_SERVER
self.c_op.flags = self._flags
self.c_op.data.receive_close_on_server.cancelled = &self._c_cancelled
- cdef void un_c(self):
+ cdef void un_c(self) except *:
self._cancelled = bool(self._c_cancelled)
def cancelled(self):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
index 7decae95bb..e17ca6d335 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
@@ -14,14 +14,16 @@
from libc.string cimport memcpy
-import pkg_resources
+import pkgutil
cdef grpc_ssl_roots_override_result ssl_roots_override_callback(
char **pem_root_certs) nogil:
with gil:
- temporary_pem_root_certs = pkg_resources.resource_string(
- __name__.rstrip('.cygrpc'), '_credentials/roots.pem')
+ pkg = __name__
+ if pkg.endswith('.cygrpc'):
+ pkg = pkg[:-len('.cygrpc')]
+ temporary_pem_root_certs = pkgutil.get_data(pkg, '_credentials/roots.pem')
pem_root_certs[0] = <char *>gpr_malloc(len(temporary_pem_root_certs) + 1)
memcpy(
pem_root_certs[0], <char *>temporary_pem_root_certs,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index 5779437b92..ce701724fd 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -18,7 +18,6 @@ import logging
import time
import grpc
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
cdef class Server:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi
index f9a3b5e8f4..d8ba1ea9bd 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi
@@ -32,7 +32,7 @@ cdef class _RequestCallTag(_Tag):
cdef CallDetails call_details
cdef grpc_metadata_array c_invocation_metadata
- cdef void prepare(self)
+ cdef void prepare(self) except *
cdef RequestCallEvent event(self, grpc_event c_event)
@@ -44,7 +44,7 @@ cdef class _BatchOperationTag(_Tag):
cdef grpc_op *c_ops
cdef size_t c_nops
- cdef void prepare(self)
+ cdef void prepare(self) except *
cdef BatchOperationEvent event(self, grpc_event c_event)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi
index aaca458442..be5013c8f7 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi
@@ -35,7 +35,7 @@ cdef class _RequestCallTag(_Tag):
self.call = None
self.call_details = None
- cdef void prepare(self):
+ cdef void prepare(self) except *:
self.call = Call()
self.call_details = CallDetails()
grpc_metadata_array_init(&self.c_invocation_metadata)
@@ -55,7 +55,7 @@ cdef class _BatchOperationTag:
self._operations = operations
self._retained_call = call
- cdef void prepare(self):
+ cdef void prepare(self) except *:
self.c_nops = 0 if self._operations is None else len(self._operations)
if 0 < self.c_nops:
self.c_ops = <grpc_op *>gpr_malloc(sizeof(grpc_op) * self.c_nops)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/time.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/time.pxd.pxi
index ce67c61eaf..1319ac0481 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/time.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/time.pxd.pxi
@@ -16,4 +16,4 @@
cdef gpr_timespec _timespec_from_time(object time)
-cdef double _time_from_timespec(gpr_timespec timespec)
+cdef double _time_from_timespec(gpr_timespec timespec) except *
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/time.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/time.pyx.pxi
index 7a668680b8..c452dd54f8 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/time.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/time.pyx.pxi
@@ -24,7 +24,7 @@ cdef gpr_timespec _timespec_from_time(object time):
return timespec
-cdef double _time_from_timespec(gpr_timespec timespec):
+cdef double _time_from_timespec(gpr_timespec timespec) except *:
cdef gpr_timespec real_timespec = gpr_convert_clock_type(
timespec, GPR_CLOCK_REALTIME)
return <double>real_timespec.seconds + <double>real_timespec.nanoseconds / 1e9
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 026f7ba2e3..9ab919375c 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -15,7 +15,6 @@
cimport cpython
-import pkg_resources
import os.path
import sys
@@ -36,6 +35,7 @@ include "_cygrpc/server.pyx.pxi"
include "_cygrpc/tag.pyx.pxi"
include "_cygrpc/time.pyx.pxi"
include "_cygrpc/_hooks.pyx.pxi"
+include "_cygrpc/channelz.pyx.pxi"
include "_cygrpc/grpc_gevent.pyx.pxi"
diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index 42b3a1ad49..7a9f173947 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
-__version__ = """1.17.0.dev0"""
+__version__ = """1.18.0.dev0"""
diff --git a/src/python/grpcio/grpc/_interceptor.py b/src/python/grpcio/grpc/_interceptor.py
index 1d2d374ad1..fc0ad77eb9 100644
--- a/src/python/grpcio/grpc/_interceptor.py
+++ b/src/python/grpcio/grpc/_interceptor.py
@@ -46,7 +46,7 @@ def service_pipeline(interceptors):
class _ClientCallDetails(
collections.namedtuple(
'_ClientCallDetails',
- ('method', 'timeout', 'metadata', 'credentials')),
+ ('method', 'timeout', 'metadata', 'credentials', 'wait_for_ready')),
grpc.ClientCallDetails):
pass
@@ -72,7 +72,12 @@ def _unwrap_client_call_details(call_details, default_details):
except AttributeError:
credentials = default_details.credentials
- return method, timeout, metadata, credentials
+ try:
+ wait_for_ready = call_details.wait_for_ready
+ except AttributeError:
+ wait_for_ready = default_details.wait_for_ready
+
+ return method, timeout, metadata, credentials, wait_for_ready
class _FailureOutcome(grpc.RpcError, grpc.Future, grpc.Call):
@@ -130,9 +135,12 @@ class _FailureOutcome(grpc.RpcError, grpc.Future, grpc.Call):
def __iter__(self):
return self
- def next(self):
+ def __next__(self):
raise self._exception
+ def next(self):
+ return self.__next__()
+
class _UnaryOutcome(grpc.Call, grpc.Future):
@@ -193,31 +201,42 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
self._method = method
self._interceptor = interceptor
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
response, ignored_call = self._with_call(
request,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
return response
- def _with_call(self, request, timeout=None, metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def _with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
try:
response, call = self._thunk(new_method).with_call(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
return _UnaryOutcome(response, call)
- except grpc.RpcError:
- raise
+ except grpc.RpcError as rpc_error:
+ return rpc_error
except Exception as exception: # pylint:disable=broad-except
return _FailureOutcome(exception, sys.exc_info()[2])
@@ -225,25 +244,37 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
continuation, client_call_details, request)
return call.result(), call
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
return self._with_call(
request,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
- def future(self, request, timeout=None, metadata=None, credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method).future(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_unary_unary(
@@ -259,18 +290,24 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
self._method = method
self._interceptor = interceptor
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method)(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_unary_stream(
@@ -290,34 +327,38 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
response, ignored_call = self._with_call(
request_iterator,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
return response
def _with_call(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
try:
response, call = self._thunk(new_method).with_call(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
return _UnaryOutcome(response, call)
- except grpc.RpcError:
- raise
+ except grpc.RpcError as rpc_error:
+ return rpc_error
except Exception as exception: # pylint:disable=broad-except
return _FailureOutcome(exception, sys.exc_info()[2])
@@ -329,29 +370,33 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
return self._with_call(
request_iterator,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
def future(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method).future(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_stream_unary(
@@ -371,18 +416,20 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method)(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_stream_stream(
diff --git a/src/python/grpcio/grpc/_plugin_wrapping.py b/src/python/grpcio/grpc/_plugin_wrapping.py
index 88ab4d8371..916ee080b6 100644
--- a/src/python/grpcio/grpc/_plugin_wrapping.py
+++ b/src/python/grpcio/grpc/_plugin_wrapping.py
@@ -20,7 +20,6 @@ import grpc
from grpc import _common
from grpc._cython import cygrpc
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index daa000a6e1..7276a7fd90 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -27,7 +27,6 @@ from grpc import _interceptor
from grpc._cython import cygrpc
from grpc.framework.foundation import callable_util
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
_SHUTDOWN_TAG = 'shutdown'
diff --git a/src/python/grpcio/grpc/beta/BUILD.bazel b/src/python/grpcio/grpc/beta/BUILD.bazel
deleted file mode 100644
index 731be5cb25..0000000000
--- a/src/python/grpcio/grpc/beta/BUILD.bazel
+++ /dev/null
@@ -1,58 +0,0 @@
-load("@grpc_python_dependencies//:requirements.bzl", "requirement")
-package(default_visibility = ["//visibility:public"])
-
-py_library(
- name = "beta",
- srcs = ["__init__.py",],
- deps = [
- ":client_adaptations",
- ":metadata",
- ":server_adaptations",
- ":implementations",
- ":interfaces",
- ":utilities",
- ],
-)
-
-py_library(
- name = "client_adaptations",
- srcs = ["_client_adaptations.py"],
- imports=["../../",]
-)
-
-py_library(
- name = "metadata",
- srcs = ["_metadata.py"],
-)
-
-py_library(
- name = "server_adaptations",
- srcs = ["_server_adaptations.py"],
- imports=["../../",],
-)
-
-py_library(
- name = "implementations",
- srcs = ["implementations.py"],
- imports=["../../",],
-)
-
-py_library(
- name = "interfaces",
- srcs = ["interfaces.py"],
- deps = [
- requirement("six"),
- ],
- imports=["../../",],
-)
-
-py_library(
- name = "utilities",
- srcs = ["utilities.py"],
- deps = [
- ":implementations",
- ":interfaces",
- "//src/python/grpcio/grpc/framework/foundation",
- ],
-)
-
diff --git a/src/python/grpcio/grpc/framework/foundation/callable_util.py b/src/python/grpcio/grpc/framework/foundation/callable_util.py
index fb8d5f7c1e..24daf3406f 100644
--- a/src/python/grpcio/grpc/framework/foundation/callable_util.py
+++ b/src/python/grpcio/grpc/framework/foundation/callable_util.py
@@ -21,7 +21,6 @@ import logging
import six
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio/grpc/framework/foundation/logging_pool.py b/src/python/grpcio/grpc/framework/foundation/logging_pool.py
index 7702d1785f..216e3990db 100644
--- a/src/python/grpcio/grpc/framework/foundation/logging_pool.py
+++ b/src/python/grpcio/grpc/framework/foundation/logging_pool.py
@@ -17,7 +17,6 @@ import logging
from concurrent import futures
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio/grpc/framework/foundation/stream_util.py b/src/python/grpcio/grpc/framework/foundation/stream_util.py
index 9184f95873..1faaf29bd7 100644
--- a/src/python/grpcio/grpc/framework/foundation/stream_util.py
+++ b/src/python/grpcio/grpc/framework/foundation/stream_util.py
@@ -19,7 +19,6 @@ import threading
from grpc.framework.foundation import stream
_NO_VALUE = object()
-logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index cb48b9f62c..ce65c594fe 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -208,12 +208,14 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
+ 'src/core/lib/uri/uri_parser.cc',
'src/core/lib/debug/trace.cc',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc',
'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+ 'src/core/ext/transport/chttp2/transport/context_list.cc',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
'src/core/ext/transport/chttp2/transport/frame_data.cc',
'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
@@ -280,7 +282,7 @@ CORE_SOURCE_FILES = [
'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
'src/core/tsi/alts/frame_protector/frame_handler.cc',
'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
- 'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+ 'src/core/tsi/alts/handshaker/alts_shared_resource.cc',
'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
@@ -322,19 +324,17 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
- 'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
+ 'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
- 'src/core/ext/filters/client_channel/uri_parser.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/client_channel/health/health.pb.c',
- 'src/core/tsi/alts_transport_security.cc',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 71113e68d9..2e91818d2c 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_channelz/.gitignore b/src/python/grpcio_channelz/.gitignore
new file mode 100644
index 0000000000..0c5da6b5af
--- /dev/null
+++ b/src/python/grpcio_channelz/.gitignore
@@ -0,0 +1,6 @@
+*.proto
+*_pb2.py
+*_pb2_grpc.py
+build/
+grpcio_channelz.egg-info/
+dist/
diff --git a/src/python/grpcio_channelz/MANIFEST.in b/src/python/grpcio_channelz/MANIFEST.in
new file mode 100644
index 0000000000..ee93e21a69
--- /dev/null
+++ b/src/python/grpcio_channelz/MANIFEST.in
@@ -0,0 +1,4 @@
+include grpc_version.py
+recursive-include grpc_channelz *.py
+global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_channelz/README.rst b/src/python/grpcio_channelz/README.rst
new file mode 100644
index 0000000000..efeaa56064
--- /dev/null
+++ b/src/python/grpcio_channelz/README.rst
@@ -0,0 +1,9 @@
+gRPC Python Channelz package
+==============================
+
+Channelz is a live debug tool in gRPC Python.
+
+Dependencies
+------------
+
+Depends on the `grpcio` package, available from PyPI via `pip install grpcio`.
diff --git a/src/python/grpcio_channelz/channelz_commands.py b/src/python/grpcio_channelz/channelz_commands.py
new file mode 100644
index 0000000000..7f158c2a4b
--- /dev/null
+++ b/src/python/grpcio_channelz/channelz_commands.py
@@ -0,0 +1,67 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Provides distutils command classes for the GRPC Python setup process."""
+
+import os
+import shutil
+
+import setuptools
+
+ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
+CHANNELZ_PROTO = os.path.join(ROOT_DIR,
+ '../../proto/grpc/channelz/channelz.proto')
+LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE')
+
+
+class Preprocess(setuptools.Command):
+ """Command to copy proto modules from grpc/src/proto and LICENSE from
+ the root directory"""
+
+ description = ''
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ if os.path.isfile(CHANNELZ_PROTO):
+ shutil.copyfile(CHANNELZ_PROTO,
+ os.path.join(ROOT_DIR,
+ 'grpc_channelz/v1/channelz.proto'))
+ if os.path.isfile(LICENSE):
+ shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE'))
+
+
+class BuildPackageProtos(setuptools.Command):
+ """Command to generate project *_pb2.py modules from proto files."""
+
+ description = 'build grpc protobuf modules'
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ # due to limitations of the proto generator, we require that only *one*
+ # directory is provided as an 'include' directory. We assume it's the '' key
+ # to `self.distribution.package_dir` (and get a key error if it's not
+ # there).
+ from grpc_tools import command
+ command.build_package_protos(self.distribution.package_dir[''])
diff --git a/src/python/grpcio_channelz/grpc_channelz/__init__.py b/src/python/grpcio_channelz/grpc_channelz/__init__.py
new file mode 100644
index 0000000000..38fdfc9c5c
--- /dev/null
+++ b/src/python/grpcio_channelz/grpc_channelz/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel b/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel
new file mode 100644
index 0000000000..aae8cedb76
--- /dev/null
+++ b/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel
@@ -0,0 +1,38 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
+
+package(default_visibility = ["//visibility:public"])
+
+genrule(
+ name = "mv_channelz_proto",
+ srcs = [
+ "//src/proto/grpc/channelz:channelz_proto_file",
+ ],
+ outs = ["channelz.proto",],
+ cmd = "cp $< $@",
+)
+
+py_proto_library(
+ name = "py_channelz_proto",
+ protos = ["mv_channelz_proto",],
+ imports = [
+ "external/com_google_protobuf/src/",
+ ],
+ inputs = [
+ "@com_google_protobuf//:well_known_protos",
+ ],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
+py_library(
+ name = "grpc_channelz",
+ srcs = ["channelz.py",],
+ deps = [
+ ":py_channelz_proto",
+ "//src/python/grpcio/grpc:grpcio",
+ ],
+ imports=["../../",],
+)
diff --git a/src/python/grpcio_channelz/grpc_channelz/v1/__init__.py b/src/python/grpcio_channelz/grpc_channelz/v1/__init__.py
new file mode 100644
index 0000000000..38fdfc9c5c
--- /dev/null
+++ b/src/python/grpcio_channelz/grpc_channelz/v1/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py b/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py
new file mode 100644
index 0000000000..573b9d0d5a
--- /dev/null
+++ b/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py
@@ -0,0 +1,141 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Channelz debug service implementation in gRPC Python."""
+
+import grpc
+from grpc._cython import cygrpc
+
+import grpc_channelz.v1.channelz_pb2 as _channelz_pb2
+import grpc_channelz.v1.channelz_pb2_grpc as _channelz_pb2_grpc
+
+from google.protobuf import json_format
+
+
+class ChannelzServicer(_channelz_pb2_grpc.ChannelzServicer):
+ """Servicer handling RPCs for service statuses."""
+
+ @staticmethod
+ def GetTopChannels(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_top_channels(request.start_channel_id),
+ _channelz_pb2.GetTopChannelsResponse(),
+ )
+ except (ValueError, json_format.ParseError) as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetServers(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_servers(request.start_server_id),
+ _channelz_pb2.GetServersResponse(),
+ )
+ except (ValueError, json_format.ParseError) as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetServer(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_server(request.server_id),
+ _channelz_pb2.GetServerResponse(),
+ )
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.NOT_FOUND)
+ context.set_details(str(e))
+ except json_format.ParseError as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetServerSockets(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_server_sockets(request.server_id,
+ request.start_socket_id),
+ _channelz_pb2.GetServerSocketsResponse(),
+ )
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.NOT_FOUND)
+ context.set_details(str(e))
+ except json_format.ParseError as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetChannel(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_channel(request.channel_id),
+ _channelz_pb2.GetChannelResponse(),
+ )
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.NOT_FOUND)
+ context.set_details(str(e))
+ except json_format.ParseError as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetSubchannel(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_subchannel(request.subchannel_id),
+ _channelz_pb2.GetSubchannelResponse(),
+ )
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.NOT_FOUND)
+ context.set_details(str(e))
+ except json_format.ParseError as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+ @staticmethod
+ def GetSocket(request, context):
+ try:
+ return json_format.Parse(
+ cygrpc.channelz_get_socket(request.socket_id),
+ _channelz_pb2.GetSocketResponse(),
+ )
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.NOT_FOUND)
+ context.set_details(str(e))
+ except json_format.ParseError as e:
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+
+
+def add_channelz_servicer(server):
+ """Add Channelz servicer to a server. Channelz servicer is in charge of
+ pulling information from C-Core for entire process. It will allow the
+ server to response to Channelz queries.
+
+ The Channelz statistic is enabled by default inside C-Core. Whether the
+ statistic is enabled or not is isolated from adding Channelz servicer.
+ That means you can query Channelz info with a Channelz-disabled channel,
+ and you can add Channelz servicer to a Channelz-disabled server.
+
+ The Channelz statistic can be enabled or disabled by channel option
+ 'grpc.enable_channelz'. Set to 1 to enable, set to 0 to disable.
+
+ This is an EXPERIMENTAL API.
+
+ Args:
+ server: grpc.Server to which Channelz service will be added.
+ """
+ _channelz_pb2_grpc.add_ChannelzServicer_to_server(ChannelzServicer(),
+ server)
diff --git a/src/python/grpcio_channelz/grpc_version.py b/src/python/grpcio_channelz/grpc_version.py
new file mode 100644
index 0000000000..16356ea402
--- /dev/null
+++ b/src/python/grpcio_channelz/grpc_version.py
@@ -0,0 +1,17 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
+
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_channelz/setup.py b/src/python/grpcio_channelz/setup.py
new file mode 100644
index 0000000000..f8c0e93913
--- /dev/null
+++ b/src/python/grpcio_channelz/setup.py
@@ -0,0 +1,96 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Setup module for the GRPC Python package's Channelz."""
+
+import os
+import sys
+
+import setuptools
+
+# Ensure we're in the proper directory whether or not we're being used by pip.
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+# Break import-style to ensure we can actually find our local modules.
+import grpc_version
+
+
+class _NoOpCommand(setuptools.Command):
+ """No-op command."""
+
+ description = ''
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ pass
+
+
+CLASSIFIERS = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'License :: OSI Approved :: Apache Software License',
+]
+
+PACKAGE_DIRECTORIES = {
+ '': '.',
+}
+
+INSTALL_REQUIRES = (
+ 'protobuf>=3.6.0',
+ 'grpcio>={version}'.format(version=grpc_version.VERSION),
+)
+
+try:
+ import channelz_commands as _channelz_commands
+ # we are in the build environment, otherwise the above import fails
+ SETUP_REQUIRES = (
+ 'grpcio-tools=={version}'.format(version=grpc_version.VERSION),)
+ COMMAND_CLASS = {
+ # Run preprocess from the repository *before* doing any packaging!
+ 'preprocess': _channelz_commands.Preprocess,
+ 'build_package_protos': _channelz_commands.BuildPackageProtos,
+ }
+except ImportError:
+ SETUP_REQUIRES = ()
+ COMMAND_CLASS = {
+ # wire up commands to no-op not to break the external dependencies
+ 'preprocess': _NoOpCommand,
+ 'build_package_protos': _NoOpCommand,
+ }
+
+setuptools.setup(
+ name='grpcio-channelz',
+ version=grpc_version.VERSION,
+ license='Apache License 2.0',
+ description='Channel Level Live Debug Information Service for gRPC',
+ author='The gRPC Authors',
+ author_email='grpc-io@googlegroups.com',
+ classifiers=CLASSIFIERS,
+ url='https://grpc.io',
+ package_dir=PACKAGE_DIRECTORIES,
+ packages=setuptools.find_packages('.'),
+ install_requires=INSTALL_REQUIRES,
+ setup_requires=SETUP_REQUIRES,
+ cmdclass=COMMAND_CLASS)
diff --git a/src/python/grpcio_health_checking/MANIFEST.in b/src/python/grpcio_health_checking/MANIFEST.in
index 996c74a9d4..3a22311b8e 100644
--- a/src/python/grpcio_health_checking/MANIFEST.in
+++ b/src/python/grpcio_health_checking/MANIFEST.in
@@ -1,3 +1,4 @@
include grpc_version.py
recursive-include grpc_health *.py
global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index a30aac2e0b..85fa762f7e 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_health_checking/health_commands.py b/src/python/grpcio_health_checking/health_commands.py
index 933f965aa2..3820ef0bba 100644
--- a/src/python/grpcio_health_checking/health_commands.py
+++ b/src/python/grpcio_health_checking/health_commands.py
@@ -20,10 +20,12 @@ import setuptools
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
HEALTH_PROTO = os.path.join(ROOT_DIR, '../../proto/grpc/health/v1/health.proto')
+LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE')
-class CopyProtoModules(setuptools.Command):
- """Command to copy proto modules from grpc/src/proto."""
+class Preprocess(setuptools.Command):
+ """Command to copy proto modules from grpc/src/proto and LICENSE from
+ the root directory"""
description = ''
user_options = []
@@ -39,6 +41,8 @@ class CopyProtoModules(setuptools.Command):
shutil.copyfile(HEALTH_PROTO,
os.path.join(ROOT_DIR,
'grpc_health/v1/health.proto'))
+ if os.path.isfile(LICENSE):
+ shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE'))
class BuildPackageProtos(setuptools.Command):
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index db2edae2ce..5a09a80f6a 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -68,7 +68,7 @@ try:
'grpcio-tools=={version}'.format(version=grpc_version.VERSION),)
COMMAND_CLASS = {
# Run preprocess from the repository *before* doing any packaging!
- 'preprocess': _health_commands.CopyProtoModules,
+ 'preprocess': _health_commands.Preprocess,
'build_package_protos': _health_commands.BuildPackageProtos,
}
except ImportError:
diff --git a/src/python/grpcio_reflection/MANIFEST.in b/src/python/grpcio_reflection/MANIFEST.in
index d6fb6ce73a..10b01fa41d 100644
--- a/src/python/grpcio_reflection/MANIFEST.in
+++ b/src/python/grpcio_reflection/MANIFEST.in
@@ -1,3 +1,4 @@
include grpc_version.py
recursive-include grpc_reflection *.py
global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel
new file mode 100644
index 0000000000..3a2ba26371
--- /dev/null
+++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel
@@ -0,0 +1,34 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
+
+package(default_visibility = ["//visibility:public"])
+
+genrule(
+ name = "mv_reflection_proto",
+ srcs = [
+ "//src/proto/grpc/reflection/v1alpha:reflection_proto_file",
+ ],
+ outs = ["reflection.proto",],
+ cmd = "cp $< $@",
+)
+
+py_proto_library(
+ name = "py_reflection_proto",
+ protos = [":mv_reflection_proto",],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
+py_library(
+ name = "grpc_reflection",
+ srcs = ["reflection.py",],
+ deps = [
+ ":py_reflection_proto",
+ "//src/python/grpcio/grpc:grpcio",
+ requirement('protobuf'),
+ ],
+ imports=["../../",],
+)
+
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index aafea9fe76..e62ab169a2 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_reflection/reflection_commands.py b/src/python/grpcio_reflection/reflection_commands.py
index 6f91f6b875..311ca4c4db 100644
--- a/src/python/grpcio_reflection/reflection_commands.py
+++ b/src/python/grpcio_reflection/reflection_commands.py
@@ -21,10 +21,12 @@ import setuptools
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
REFLECTION_PROTO = os.path.join(
ROOT_DIR, '../../proto/grpc/reflection/v1alpha/reflection.proto')
+LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE')
-class CopyProtoModules(setuptools.Command):
- """Command to copy proto modules from grpc/src/proto."""
+class Preprocess(setuptools.Command):
+ """Command to copy proto modules from grpc/src/proto and LICENSE from
+ the root directory"""
description = ''
user_options = []
@@ -41,6 +43,8 @@ class CopyProtoModules(setuptools.Command):
REFLECTION_PROTO,
os.path.join(ROOT_DIR,
'grpc_reflection/v1alpha/reflection.proto'))
+ if os.path.isfile(LICENSE):
+ shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE'))
class BuildPackageProtos(setuptools.Command):
diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py
index b4087d87b4..f205069acd 100644
--- a/src/python/grpcio_reflection/setup.py
+++ b/src/python/grpcio_reflection/setup.py
@@ -69,7 +69,7 @@ try:
'grpcio-tools=={version}'.format(version=grpc_version.VERSION),)
COMMAND_CLASS = {
# Run preprocess from the repository *before* doing any packaging!
- 'preprocess': _reflection_commands.CopyProtoModules,
+ 'preprocess': _reflection_commands.Preprocess,
'build_package_protos': _reflection_commands.BuildPackageProtos,
}
except ImportError:
diff --git a/src/python/grpcio_testing/MANIFEST.in b/src/python/grpcio_testing/MANIFEST.in
index 39b3565217..559dfaf786 100644
--- a/src/python/grpcio_testing/MANIFEST.in
+++ b/src/python/grpcio_testing/MANIFEST.in
@@ -1,3 +1,4 @@
include grpc_version.py
recursive-include grpc_testing *.py
global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index 876acd3142..7b4c1695fa 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_testing/setup.py b/src/python/grpcio_testing/setup.py
index 6ceb1fc5c9..18db71e0f0 100644
--- a/src/python/grpcio_testing/setup.py
+++ b/src/python/grpcio_testing/setup.py
@@ -24,6 +24,23 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import style to ensure that we can find same-directory modules.
import grpc_version
+
+class _NoOpCommand(setuptools.Command):
+ """No-op command."""
+
+ description = ''
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ pass
+
+
PACKAGE_DIRECTORIES = {
'': '.',
}
@@ -33,6 +50,19 @@ INSTALL_REQUIRES = (
'grpcio>={version}'.format(version=grpc_version.VERSION),
)
+try:
+ import testing_commands as _testing_commands
+ # we are in the build environment, otherwise the above import fails
+ COMMAND_CLASS = {
+ # Run preprocess from the repository *before* doing any packaging!
+ 'preprocess': _testing_commands.Preprocess,
+ }
+except ImportError:
+ COMMAND_CLASS = {
+ # wire up commands to no-op not to break the external dependencies
+ 'preprocess': _NoOpCommand,
+ }
+
setuptools.setup(
name='grpcio-testing',
version=grpc_version.VERSION,
@@ -43,4 +73,5 @@ setuptools.setup(
url='https://grpc.io',
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages('.'),
- install_requires=INSTALL_REQUIRES)
+ install_requires=INSTALL_REQUIRES,
+ cmdclass=COMMAND_CLASS)
diff --git a/src/python/grpcio_testing/testing_commands.py b/src/python/grpcio_testing/testing_commands.py
new file mode 100644
index 0000000000..fb40d37efb
--- /dev/null
+++ b/src/python/grpcio_testing/testing_commands.py
@@ -0,0 +1,39 @@
+# Copyright 2018 gRPC Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Provides distutils command classes for the GRPC Python setup process."""
+
+import os
+import shutil
+
+import setuptools
+
+ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
+LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE')
+
+
+class Preprocess(setuptools.Command):
+ """Command to copy LICENSE from root directory."""
+
+ description = ''
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ if os.path.isfile(LICENSE):
+ shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE'))
diff --git a/src/python/grpcio_tests/commands.py b/src/python/grpcio_tests/commands.py
index 6931d93ef0..65e9a99950 100644
--- a/src/python/grpcio_tests/commands.py
+++ b/src/python/grpcio_tests/commands.py
@@ -130,6 +130,13 @@ class TestGevent(setuptools.Command):
# Beta API is unsupported for gevent
'protoc_plugin.beta_python_plugin_test',
'unit.beta._beta_features_test',
+ # TODO(https://github.com/grpc/grpc/issues/15411) unpin gevent version
+ # This test will stuck while running higher version of gevent
+ 'unit._auth_context_test.AuthContextTest.testSessionResumption',
+ # TODO(https://github.com/grpc/grpc/issues/17330) enable these three tests
+ 'channelz._channelz_servicer_test.ChannelzServicerTest.test_many_subchannels',
+ 'channelz._channelz_servicer_test.ChannelzServicerTest.test_many_subchannels_and_sockets',
+ 'channelz._channelz_servicer_test.ChannelzServicerTest.test_streaming_rpc'
)
description = 'run tests with gevent. Assumes grpc/gevent are installed'
user_options = []
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index cc9b41587c..2fcd1ad617 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 61c98fa038..f56425ac6d 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -39,6 +39,7 @@ PACKAGE_DIRECTORIES = {
INSTALL_REQUIRES = (
'coverage>=4.0', 'enum34>=1.0.4',
'grpcio>={version}'.format(version=grpc_version.VERSION),
+ 'grpcio-channelz>={version}'.format(version=grpc_version.VERSION),
'grpcio-tools>={version}'.format(version=grpc_version.VERSION),
'grpcio-health-checking>={version}'.format(version=grpc_version.VERSION),
'oauth2client>=1.4.7', 'protobuf>=3.6.0', 'six>=1.10', 'google-auth>=1.0.0',
diff --git a/src/python/grpcio_tests/tests/_sanity/_sanity_test.py b/src/python/grpcio_tests/tests/_sanity/_sanity_test.py
index b4079850ff..7da6e7b34c 100644
--- a/src/python/grpcio_tests/tests/_sanity/_sanity_test.py
+++ b/src/python/grpcio_tests/tests/_sanity/_sanity_test.py
@@ -13,9 +13,9 @@
# limitations under the License.
import json
+import pkgutil
import unittest
-import pkg_resources
import six
import tests
@@ -35,7 +35,7 @@ class SanityTest(unittest.TestCase):
loader.suite)
})
- tests_json_string = pkg_resources.resource_string('tests', 'tests.json')
+ tests_json_string = pkgutil.get_data('tests', 'tests.json')
tests_json = json.loads(tests_json_string.decode()
if six.PY3 else tests_json_string)
diff --git a/src/python/grpcio_tests/tests/channelz/BUILD.bazel b/src/python/grpcio_tests/tests/channelz/BUILD.bazel
new file mode 100644
index 0000000000..63513616e7
--- /dev/null
+++ b/src/python/grpcio_tests/tests/channelz/BUILD.bazel
@@ -0,0 +1,15 @@
+package(default_visibility = ["//visibility:public"])
+
+py_test(
+ name = "channelz_servicer_test",
+ srcs = ["_channelz_servicer_test.py"],
+ main = "_channelz_servicer_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/python/grpcio_tests/tests/unit/framework/common:common",
+ ],
+ imports = ["../../",],
+)
diff --git a/src/python/grpcio_tests/tests/channelz/__init__.py b/src/python/grpcio_tests/tests/channelz/__init__.py
new file mode 100644
index 0000000000..38fdfc9c5c
--- /dev/null
+++ b/src/python/grpcio_tests/tests/channelz/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py b/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py
new file mode 100644
index 0000000000..8ca5189522
--- /dev/null
+++ b/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py
@@ -0,0 +1,470 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests of grpc_channelz.v1.channelz."""
+
+import unittest
+
+from concurrent import futures
+
+import grpc
+from grpc_channelz.v1 import channelz
+from grpc_channelz.v1 import channelz_pb2
+from grpc_channelz.v1 import channelz_pb2_grpc
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+
+_SUCCESSFUL_UNARY_UNARY = '/test/SuccessfulUnaryUnary'
+_FAILED_UNARY_UNARY = '/test/FailedUnaryUnary'
+_SUCCESSFUL_STREAM_STREAM = '/test/SuccessfulStreamStream'
+
+_REQUEST = b'\x00\x00\x00'
+_RESPONSE = b'\x01\x01\x01'
+
+_DISABLE_REUSE_PORT = (('grpc.so_reuseport', 0),)
+_ENABLE_CHANNELZ = (('grpc.enable_channelz', 1),)
+_DISABLE_CHANNELZ = (('grpc.enable_channelz', 0),)
+
+
+def _successful_unary_unary(request, servicer_context):
+ return _RESPONSE
+
+
+def _failed_unary_unary(request, servicer_context):
+ servicer_context.set_code(grpc.StatusCode.INTERNAL)
+ servicer_context.set_details("Channelz Test Intended Failure")
+
+
+def _successful_stream_stream(request_iterator, servicer_context):
+ for _ in request_iterator:
+ yield _RESPONSE
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def service(self, handler_call_details):
+ if handler_call_details.method == _SUCCESSFUL_UNARY_UNARY:
+ return grpc.unary_unary_rpc_method_handler(_successful_unary_unary)
+ elif handler_call_details.method == _FAILED_UNARY_UNARY:
+ return grpc.unary_unary_rpc_method_handler(_failed_unary_unary)
+ elif handler_call_details.method == _SUCCESSFUL_STREAM_STREAM:
+ return grpc.stream_stream_rpc_method_handler(
+ _successful_stream_stream)
+ else:
+ return None
+
+
+class _ChannelServerPair(object):
+
+ def __init__(self):
+ # Server will enable channelz service
+ self.server = grpc.server(
+ futures.ThreadPoolExecutor(max_workers=3),
+ options=_DISABLE_REUSE_PORT + _ENABLE_CHANNELZ)
+ port = self.server.add_insecure_port('[::]:0')
+ self.server.add_generic_rpc_handlers((_GenericHandler(),))
+ self.server.start()
+
+ # Channel will enable channelz service...
+ self.channel = grpc.insecure_channel('localhost:%d' % port,
+ _ENABLE_CHANNELZ)
+
+
+def _generate_channel_server_pairs(n):
+ return [_ChannelServerPair() for i in range(n)]
+
+
+def _close_channel_server_pairs(pairs):
+ for pair in pairs:
+ pair.server.stop(None)
+ # TODO(ericgribkoff) This del should not be required
+ del pair.server
+ pair.channel.close()
+
+
+class ChannelzServicerTest(unittest.TestCase):
+
+ def _send_successful_unary_unary(self, idx):
+ _, r = self._pairs[idx].channel.unary_unary(
+ _SUCCESSFUL_UNARY_UNARY).with_call(_REQUEST)
+ self.assertEqual(r.code(), grpc.StatusCode.OK)
+
+ def _send_failed_unary_unary(self, idx):
+ try:
+ self._pairs[idx].channel.unary_unary(_FAILED_UNARY_UNARY).with_call(
+ _REQUEST)
+ except grpc.RpcError:
+ return
+ else:
+ self.fail("This call supposed to fail")
+
+ def _send_successful_stream_stream(self, idx):
+ response_iterator = self._pairs[idx].channel.stream_stream(
+ _SUCCESSFUL_STREAM_STREAM).__call__(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH))
+ cnt = 0
+ for _ in response_iterator:
+ cnt += 1
+ self.assertEqual(cnt, test_constants.STREAM_LENGTH)
+
+ def _get_channel_id(self, idx):
+ """Channel id may not be consecutive"""
+ resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=0))
+ self.assertGreater(len(resp.channel), idx)
+ return resp.channel[idx].ref.channel_id
+
+ def setUp(self):
+ self._pairs = []
+ # This server is for Channelz info fetching only
+ # It self should not enable Channelz
+ self._server = grpc.server(
+ futures.ThreadPoolExecutor(max_workers=3),
+ options=_DISABLE_REUSE_PORT + _DISABLE_CHANNELZ)
+ port = self._server.add_insecure_port('[::]:0')
+ channelz.add_channelz_servicer(self._server)
+ self._server.start()
+
+ # This channel is used to fetch Channelz info only
+ # Channelz should not be enabled
+ self._channel = grpc.insecure_channel('localhost:%d' % port,
+ _DISABLE_CHANNELZ)
+ self._channelz_stub = channelz_pb2_grpc.ChannelzStub(self._channel)
+
+ def tearDown(self):
+ self._server.stop(None)
+ self._channel.close()
+ _close_channel_server_pairs(self._pairs)
+
+ def test_get_top_channels_basic(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=0))
+ self.assertEqual(len(resp.channel), 1)
+ self.assertEqual(resp.end, True)
+
+ def test_get_top_channels_high_start_id(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=10000))
+ self.assertEqual(len(resp.channel), 0)
+ self.assertEqual(resp.end, True)
+
+ def test_successful_request(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ self._send_successful_unary_unary(0)
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(0)))
+ self.assertEqual(resp.channel.data.calls_started, 1)
+ self.assertEqual(resp.channel.data.calls_succeeded, 1)
+ self.assertEqual(resp.channel.data.calls_failed, 0)
+
+ def test_failed_request(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ self._send_failed_unary_unary(0)
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(0)))
+ self.assertEqual(resp.channel.data.calls_started, 1)
+ self.assertEqual(resp.channel.data.calls_succeeded, 0)
+ self.assertEqual(resp.channel.data.calls_failed, 1)
+
+ def test_many_requests(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ k_success = 7
+ k_failed = 9
+ for i in range(k_success):
+ self._send_successful_unary_unary(0)
+ for i in range(k_failed):
+ self._send_failed_unary_unary(0)
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(0)))
+ self.assertEqual(resp.channel.data.calls_started, k_success + k_failed)
+ self.assertEqual(resp.channel.data.calls_succeeded, k_success)
+ self.assertEqual(resp.channel.data.calls_failed, k_failed)
+
+ def test_many_channel(self):
+ k_channels = 4
+ self._pairs = _generate_channel_server_pairs(k_channels)
+ resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=0))
+ self.assertEqual(len(resp.channel), k_channels)
+
+ def test_many_requests_many_channel(self):
+ k_channels = 4
+ self._pairs = _generate_channel_server_pairs(k_channels)
+ k_success = 11
+ k_failed = 13
+ for i in range(k_success):
+ self._send_successful_unary_unary(0)
+ self._send_successful_unary_unary(2)
+ for i in range(k_failed):
+ self._send_failed_unary_unary(1)
+ self._send_failed_unary_unary(2)
+
+ # The first channel saw only successes
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(0)))
+ self.assertEqual(resp.channel.data.calls_started, k_success)
+ self.assertEqual(resp.channel.data.calls_succeeded, k_success)
+ self.assertEqual(resp.channel.data.calls_failed, 0)
+
+ # The second channel saw only failures
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(1)))
+ self.assertEqual(resp.channel.data.calls_started, k_failed)
+ self.assertEqual(resp.channel.data.calls_succeeded, 0)
+ self.assertEqual(resp.channel.data.calls_failed, k_failed)
+
+ # The third channel saw both successes and failures
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(2)))
+ self.assertEqual(resp.channel.data.calls_started, k_success + k_failed)
+ self.assertEqual(resp.channel.data.calls_succeeded, k_success)
+ self.assertEqual(resp.channel.data.calls_failed, k_failed)
+
+ # The fourth channel saw nothing
+ resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(3)))
+ self.assertEqual(resp.channel.data.calls_started, 0)
+ self.assertEqual(resp.channel.data.calls_succeeded, 0)
+ self.assertEqual(resp.channel.data.calls_failed, 0)
+
+ def test_many_subchannels(self):
+ k_channels = 4
+ self._pairs = _generate_channel_server_pairs(k_channels)
+ k_success = 17
+ k_failed = 19
+ for i in range(k_success):
+ self._send_successful_unary_unary(0)
+ self._send_successful_unary_unary(2)
+ for i in range(k_failed):
+ self._send_failed_unary_unary(1)
+ self._send_failed_unary_unary(2)
+
+ gtc_resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=0))
+ self.assertEqual(len(gtc_resp.channel), k_channels)
+ for i in range(k_channels):
+ # If no call performed in the channel, there shouldn't be any subchannel
+ if gtc_resp.channel[i].data.calls_started == 0:
+ self.assertEqual(len(gtc_resp.channel[i].subchannel_ref), 0)
+ continue
+
+ # Otherwise, the subchannel should exist
+ self.assertGreater(len(gtc_resp.channel[i].subchannel_ref), 0)
+ gsc_resp = self._channelz_stub.GetSubchannel(
+ channelz_pb2.GetSubchannelRequest(
+ subchannel_id=gtc_resp.channel[i].subchannel_ref[
+ 0].subchannel_id))
+ self.assertEqual(gtc_resp.channel[i].data.calls_started,
+ gsc_resp.subchannel.data.calls_started)
+ self.assertEqual(gtc_resp.channel[i].data.calls_succeeded,
+ gsc_resp.subchannel.data.calls_succeeded)
+ self.assertEqual(gtc_resp.channel[i].data.calls_failed,
+ gsc_resp.subchannel.data.calls_failed)
+
+ def test_server_basic(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ resp = self._channelz_stub.GetServers(
+ channelz_pb2.GetServersRequest(start_server_id=0))
+ self.assertEqual(len(resp.server), 1)
+
+ def test_get_one_server(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ gss_resp = self._channelz_stub.GetServers(
+ channelz_pb2.GetServersRequest(start_server_id=0))
+ self.assertEqual(len(gss_resp.server), 1)
+ gs_resp = self._channelz_stub.GetServer(
+ channelz_pb2.GetServerRequest(
+ server_id=gss_resp.server[0].ref.server_id))
+ self.assertEqual(gss_resp.server[0].ref.server_id,
+ gs_resp.server.ref.server_id)
+
+ def test_server_call(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ k_success = 23
+ k_failed = 29
+ for i in range(k_success):
+ self._send_successful_unary_unary(0)
+ for i in range(k_failed):
+ self._send_failed_unary_unary(0)
+
+ resp = self._channelz_stub.GetServers(
+ channelz_pb2.GetServersRequest(start_server_id=0))
+ self.assertEqual(len(resp.server), 1)
+ self.assertEqual(resp.server[0].data.calls_started,
+ k_success + k_failed)
+ self.assertEqual(resp.server[0].data.calls_succeeded, k_success)
+ self.assertEqual(resp.server[0].data.calls_failed, k_failed)
+
+ def test_many_subchannels_and_sockets(self):
+ k_channels = 4
+ self._pairs = _generate_channel_server_pairs(k_channels)
+ k_success = 3
+ k_failed = 5
+ for i in range(k_success):
+ self._send_successful_unary_unary(0)
+ self._send_successful_unary_unary(2)
+ for i in range(k_failed):
+ self._send_failed_unary_unary(1)
+ self._send_failed_unary_unary(2)
+
+ gtc_resp = self._channelz_stub.GetTopChannels(
+ channelz_pb2.GetTopChannelsRequest(start_channel_id=0))
+ self.assertEqual(len(gtc_resp.channel), k_channels)
+ for i in range(k_channels):
+ # If no call performed in the channel, there shouldn't be any subchannel
+ if gtc_resp.channel[i].data.calls_started == 0:
+ self.assertEqual(len(gtc_resp.channel[i].subchannel_ref), 0)
+ continue
+
+ # Otherwise, the subchannel should exist
+ self.assertGreater(len(gtc_resp.channel[i].subchannel_ref), 0)
+ gsc_resp = self._channelz_stub.GetSubchannel(
+ channelz_pb2.GetSubchannelRequest(
+ subchannel_id=gtc_resp.channel[i].subchannel_ref[
+ 0].subchannel_id))
+ self.assertEqual(len(gsc_resp.subchannel.socket_ref), 1)
+
+ gs_resp = self._channelz_stub.GetSocket(
+ channelz_pb2.GetSocketRequest(
+ socket_id=gsc_resp.subchannel.socket_ref[0].socket_id))
+ self.assertEqual(gsc_resp.subchannel.data.calls_started,
+ gs_resp.socket.data.streams_started)
+ self.assertEqual(gsc_resp.subchannel.data.calls_started,
+ gs_resp.socket.data.streams_succeeded)
+ # Calls started == messages sent, only valid for unary calls
+ self.assertEqual(gsc_resp.subchannel.data.calls_started,
+ gs_resp.socket.data.messages_sent)
+ # Only receive responses when the RPC was successful
+ self.assertEqual(gsc_resp.subchannel.data.calls_succeeded,
+ gs_resp.socket.data.messages_received)
+
+ def test_streaming_rpc(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ # In C++, the argument for _send_successful_stream_stream is message length.
+ # Here the argument is still channel idx, to be consistent with the other two.
+ self._send_successful_stream_stream(0)
+
+ gc_resp = self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=self._get_channel_id(0)))
+ self.assertEqual(gc_resp.channel.data.calls_started, 1)
+ self.assertEqual(gc_resp.channel.data.calls_succeeded, 1)
+ self.assertEqual(gc_resp.channel.data.calls_failed, 0)
+ # Subchannel exists
+ self.assertGreater(len(gc_resp.channel.subchannel_ref), 0)
+
+ gsc_resp = self._channelz_stub.GetSubchannel(
+ channelz_pb2.GetSubchannelRequest(
+ subchannel_id=gc_resp.channel.subchannel_ref[0].subchannel_id))
+ self.assertEqual(gsc_resp.subchannel.data.calls_started, 1)
+ self.assertEqual(gsc_resp.subchannel.data.calls_succeeded, 1)
+ self.assertEqual(gsc_resp.subchannel.data.calls_failed, 0)
+ # Socket exists
+ self.assertEqual(len(gsc_resp.subchannel.socket_ref), 1)
+
+ gs_resp = self._channelz_stub.GetSocket(
+ channelz_pb2.GetSocketRequest(
+ socket_id=gsc_resp.subchannel.socket_ref[0].socket_id))
+ self.assertEqual(gs_resp.socket.data.streams_started, 1)
+ self.assertEqual(gs_resp.socket.data.streams_succeeded, 1)
+ self.assertEqual(gs_resp.socket.data.streams_failed, 0)
+ self.assertEqual(gs_resp.socket.data.messages_sent,
+ test_constants.STREAM_LENGTH)
+ self.assertEqual(gs_resp.socket.data.messages_received,
+ test_constants.STREAM_LENGTH)
+
+ def test_server_sockets(self):
+ self._pairs = _generate_channel_server_pairs(1)
+ self._send_successful_unary_unary(0)
+ self._send_failed_unary_unary(0)
+
+ gs_resp = self._channelz_stub.GetServers(
+ channelz_pb2.GetServersRequest(start_server_id=0))
+ self.assertEqual(len(gs_resp.server), 1)
+ self.assertEqual(gs_resp.server[0].data.calls_started, 2)
+ self.assertEqual(gs_resp.server[0].data.calls_succeeded, 1)
+ self.assertEqual(gs_resp.server[0].data.calls_failed, 1)
+
+ gss_resp = self._channelz_stub.GetServerSockets(
+ channelz_pb2.GetServerSocketsRequest(
+ server_id=gs_resp.server[0].ref.server_id, start_socket_id=0))
+ # If the RPC call failed, it will raise a grpc.RpcError
+ # So, if there is no exception raised, considered pass
+
+ def test_server_listen_sockets(self):
+ self._pairs = _generate_channel_server_pairs(1)
+
+ gss_resp = self._channelz_stub.GetServers(
+ channelz_pb2.GetServersRequest(start_server_id=0))
+ self.assertEqual(len(gss_resp.server), 1)
+ self.assertEqual(len(gss_resp.server[0].listen_socket), 1)
+
+ gs_resp = self._channelz_stub.GetSocket(
+ channelz_pb2.GetSocketRequest(
+ socket_id=gss_resp.server[0].listen_socket[0].socket_id))
+ # If the RPC call failed, it will raise a grpc.RpcError
+ # So, if there is no exception raised, considered pass
+
+ def test_invalid_query_get_server(self):
+ try:
+ self._channelz_stub.GetServer(
+ channelz_pb2.GetServerRequest(server_id=10000))
+ except BaseException as e:
+ self.assertIn('StatusCode.NOT_FOUND', str(e))
+ else:
+ self.fail('Invalid query not detected')
+
+ def test_invalid_query_get_channel(self):
+ try:
+ self._channelz_stub.GetChannel(
+ channelz_pb2.GetChannelRequest(channel_id=10000))
+ except BaseException as e:
+ self.assertIn('StatusCode.NOT_FOUND', str(e))
+ else:
+ self.fail('Invalid query not detected')
+
+ def test_invalid_query_get_subchannel(self):
+ try:
+ self._channelz_stub.GetSubchannel(
+ channelz_pb2.GetSubchannelRequest(subchannel_id=10000))
+ except BaseException as e:
+ self.assertIn('StatusCode.NOT_FOUND', str(e))
+ else:
+ self.fail('Invalid query not detected')
+
+ def test_invalid_query_get_socket(self):
+ try:
+ self._channelz_stub.GetSocket(
+ channelz_pb2.GetSocketRequest(socket_id=10000))
+ except BaseException as e:
+ self.assertIn('StatusCode.NOT_FOUND', str(e))
+ else:
+ self.fail('Invalid query not detected')
+
+ def test_invalid_query_get_server_sockets(self):
+ try:
+ self._channelz_stub.GetServerSockets(
+ channelz_pb2.GetServerSocketsRequest(
+ server_id=10000,
+ start_socket_id=0,
+ ))
+ except BaseException as e:
+ self.assertIn('StatusCode.NOT_FOUND', str(e))
+ else:
+ self.fail('Invalid query not detected')
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/interop/BUILD.bazel b/src/python/grpcio_tests/tests/interop/BUILD.bazel
new file mode 100644
index 0000000000..aebdbf67eb
--- /dev/null
+++ b/src/python/grpcio_tests/tests/interop/BUILD.bazel
@@ -0,0 +1,101 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+ name = "_intraop_test_case",
+ srcs = ["_intraop_test_case.py"],
+ deps = [
+ ":methods",
+ ],
+ imports=["../../",],
+)
+
+py_library(
+ name = "client",
+ srcs = ["client.py"],
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ ":methods",
+ ":resources",
+ "//src/proto/grpc/testing:py_test_proto",
+ requirement('google-auth'),
+ ],
+ imports=["../../",],
+)
+
+py_library(
+ name = "methods",
+ srcs = ["methods.py"],
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/proto/grpc/testing:py_empty_proto",
+ "//src/proto/grpc/testing:py_messages_proto",
+ "//src/proto/grpc/testing:py_test_proto",
+ requirement('google-auth'),
+ requirement('requests'),
+ requirement('enum34'),
+ requirement('urllib3'),
+ requirement('chardet'),
+ requirement('certifi'),
+ requirement('idna'),
+ ],
+ imports=["../../",],
+)
+
+py_library(
+ name = "resources",
+ srcs = ["resources.py"],
+ data = [
+ "//src/python/grpcio_tests/tests/interop/credentials",
+ ],
+)
+
+py_library(
+ name = "server",
+ srcs = ["server.py"],
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ ":methods",
+ ":resources",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/proto/grpc/testing:py_test_proto",
+ ],
+ imports=["../../",],
+)
+
+py_test(
+ name="_insecure_intraop_test",
+ size="small",
+ srcs=["_insecure_intraop_test.py",],
+ main="_insecure_intraop_test.py",
+ deps=[
+ "//src/python/grpcio/grpc:grpcio",
+ ":_intraop_test_case",
+ ":methods",
+ ":server",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/proto/grpc/testing:py_test_proto",
+ ],
+ imports=["../../",],
+ data=[
+ "//src/python/grpcio_tests/tests/unit/credentials",
+ ],
+)
+
+py_test(
+ name="_secure_intraop_test",
+ size="small",
+ srcs=["_secure_intraop_test.py",],
+ main="_secure_intraop_test.py",
+ deps=[
+ "//src/python/grpcio/grpc:grpcio",
+ ":_intraop_test_case",
+ ":methods",
+ ":server",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/proto/grpc/testing:py_test_proto",
+ ],
+ imports=["../../",],
+)
+
diff --git a/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel b/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel
new file mode 100644
index 0000000000..bc2b997292
--- /dev/null
+++ b/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel
@@ -0,0 +1,9 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name="credentials",
+ srcs=glob([
+ "**",
+ ]),
+)
+
diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py
index cda15a68a3..c11f6c8fad 100644
--- a/src/python/grpcio_tests/tests/interop/methods.py
+++ b/src/python/grpcio_tests/tests/interop/methods.py
@@ -23,7 +23,6 @@ from google.auth import environment_vars as google_auth_environment_vars
from google.auth.transport import grpc as google_auth_transport_grpc
from google.auth.transport import requests as google_auth_transport_requests
import grpc
-from grpc.beta import implementations
from src.proto.grpc.testing import empty_pb2
from src.proto.grpc.testing import messages_pb2
@@ -377,7 +376,7 @@ def _unimplemented_service(unimplemented_service_stub):
def _custom_metadata(stub):
initial_metadata_value = "test_initial_metadata_value"
- trailing_metadata_value = "\x0a\x0b\x0a\x0b\x0a\x0b"
+ trailing_metadata_value = b"\x0a\x0b\x0a\x0b\x0a\x0b"
metadata = ((_INITIAL_METADATA_KEY, initial_metadata_value),
(_TRAILING_METADATA_KEY, trailing_metadata_value))
@@ -391,7 +390,7 @@ def _custom_metadata(stub):
if trailing_metadata[_TRAILING_METADATA_KEY] != trailing_metadata_value:
raise ValueError('expected trailing metadata %s, got %s' %
(trailing_metadata_value,
- initial_metadata[_TRAILING_METADATA_KEY]))
+ trailing_metadata[_TRAILING_METADATA_KEY]))
# Testing with UnaryCall
request = messages_pb2.SimpleRequest(
@@ -422,7 +421,7 @@ def _compute_engine_creds(stub, args):
def _oauth2_auth_token(stub, args):
json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
- wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
+ wanted_email = json.load(open(json_key_filename, 'r'))['client_email']
response = _large_unary_common_behavior(stub, True, True, None)
if wanted_email != response.username:
raise ValueError('expected username %s, got %s' % (wanted_email,
@@ -435,7 +434,7 @@ def _oauth2_auth_token(stub, args):
def _jwt_token_creds(stub, args):
json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
- wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
+ wanted_email = json.load(open(json_key_filename, 'r'))['client_email']
response = _large_unary_common_behavior(stub, True, False, None)
if wanted_email != response.username:
raise ValueError('expected username %s, got %s' % (wanted_email,
@@ -444,7 +443,7 @@ def _jwt_token_creds(stub, args):
def _per_rpc_creds(stub, args):
json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
- wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
+ wanted_email = json.load(open(json_key_filename, 'r'))['client_email']
google_credentials, unused_project_id = google_auth.default(
scopes=[args.oauth_scope])
call_credentials = grpc.metadata_call_credentials(
@@ -457,6 +456,22 @@ def _per_rpc_creds(stub, args):
response.username))
+def _special_status_message(stub, args):
+ details = b'\t\ntest with whitespace\r\nand Unicode BMP \xe2\x98\xba and non-BMP \xf0\x9f\x98\x88\t\n'.decode(
+ 'utf-8')
+ code = 2
+ status = grpc.StatusCode.UNKNOWN # code = 2
+
+ # Test with a UnaryCall
+ request = messages_pb2.SimpleRequest(
+ response_type=messages_pb2.COMPRESSABLE,
+ response_size=1,
+ payload=messages_pb2.Payload(body=b'\x00'),
+ response_status=messages_pb2.EchoStatus(code=code, message=details))
+ response_future = stub.UnaryCall.future(request)
+ _validate_status_code_and_details(response_future, status, details)
+
+
@enum.unique
class TestCase(enum.Enum):
EMPTY_UNARY = 'empty_unary'
@@ -476,6 +491,7 @@ class TestCase(enum.Enum):
JWT_TOKEN_CREDS = 'jwt_token_creds'
PER_RPC_CREDS = 'per_rpc_creds'
TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server'
+ SPECIAL_STATUS_MESSAGE = 'special_status_message'
def test_interoperability(self, stub, args):
if self is TestCase.EMPTY_UNARY:
@@ -512,6 +528,8 @@ class TestCase(enum.Enum):
_jwt_token_creds(stub, args)
elif self is TestCase.PER_RPC_CREDS:
_per_rpc_creds(stub, args)
+ elif self is TestCase.SPECIAL_STATUS_MESSAGE:
+ _special_status_message(stub, args)
else:
raise NotImplementedError(
'Test case "%s" not implemented!' % self.name)
diff --git a/src/python/grpcio_tests/tests/interop/resources.py b/src/python/grpcio_tests/tests/interop/resources.py
index 2f76cf5db6..a55919a60a 100644
--- a/src/python/grpcio_tests/tests/interop/resources.py
+++ b/src/python/grpcio_tests/tests/interop/resources.py
@@ -14,27 +14,24 @@
"""Constants and functions for data used in interoperability testing."""
import argparse
+import pkgutil
import os
-import pkg_resources
-
_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem'
_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
_CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
def test_root_certificates():
- return pkg_resources.resource_string(__name__,
- _ROOT_CERTIFICATES_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
def private_key():
- return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _PRIVATE_KEY_RESOURCE_PATH)
def certificate_chain():
- return pkg_resources.resource_string(__name__,
- _CERTIFICATE_CHAIN_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
def parse_bool(value):
diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py
index 768cdaf468..72f88a1c98 100644
--- a/src/python/grpcio_tests/tests/interop/server.py
+++ b/src/python/grpcio_tests/tests/interop/server.py
@@ -25,8 +25,8 @@ from tests.interop import methods
from tests.interop import resources
from tests.unit import test_common
-logging.basicConfig()
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio_tests/tests/qps/worker_server.py b/src/python/grpcio_tests/tests/qps/worker_server.py
index 740bdcf1eb..337a94b546 100644
--- a/src/python/grpcio_tests/tests/qps/worker_server.py
+++ b/src/python/grpcio_tests/tests/qps/worker_server.py
@@ -39,7 +39,7 @@ class WorkerServer(worker_service_pb2_grpc.WorkerServiceServicer):
self._quit_event = threading.Event()
def RunServer(self, request_iterator, context):
- config = next(request_iterator).setup
+ config = next(request_iterator).setup #pylint: disable=stop-iteration-return
server, port = self._create_server(config)
cores = multiprocessing.cpu_count()
server.start()
@@ -102,7 +102,7 @@ class WorkerServer(worker_service_pb2_grpc.WorkerServiceServicer):
return (server, port)
def RunClient(self, request_iterator, context):
- config = next(request_iterator).setup
+ config = next(request_iterator).setup #pylint: disable=stop-iteration-return
client_runners = []
qps_data = histogram.Histogram(config.histogram_params.resolution,
config.histogram_params.max_possible)
diff --git a/src/python/grpcio_tests/tests/reflection/BUILD.bazel b/src/python/grpcio_tests/tests/reflection/BUILD.bazel
new file mode 100644
index 0000000000..c0efb0b7ce
--- /dev/null
+++ b/src/python/grpcio_tests/tests/reflection/BUILD.bazel
@@ -0,0 +1,21 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+package(default_visibility = ["//visibility:public"])
+
+py_test(
+ name="_reflection_servicer_test",
+ size="small",
+ timeout="moderate",
+ srcs=["_reflection_servicer_test.py",],
+ main="_reflection_servicer_test.py",
+ deps=[
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_reflection/grpc_reflection/v1alpha:grpc_reflection",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/proto/grpc/testing:py_empty_proto",
+ "//src/proto/grpc/testing/proto2:empty2_extensions_proto",
+ requirement('protobuf'),
+ ],
+ imports=["../../",],
+)
+
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 76d5d22d57..9cffd3df19 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -1,5 +1,6 @@
[
"_sanity._sanity_test.SanityTest",
+ "channelz._channelz_servicer_test.ChannelzServicerTest",
"health_check._health_servicer_test.HealthServicerTest",
"interop._insecure_intraop_test.InsecureIntraopTest",
"interop._secure_intraop_test.SecureIntraopTest",
@@ -42,11 +43,14 @@
"unit._cython.cygrpc_test.SecureServerSecureClient",
"unit._cython.cygrpc_test.TypeSmokeTest",
"unit._empty_message_test.EmptyMessageTest",
+ "unit._error_message_encoding_test.ErrorMessageEncodingTest",
"unit._exit_test.ExitTest",
"unit._interceptor_test.InterceptorTest",
"unit._invalid_metadata_test.InvalidMetadataTest",
"unit._invocation_defects_test.InvocationDefectsTest",
+ "unit._logging_test.LoggingTest",
"unit._metadata_code_details_test.MetadataCodeDetailsTest",
+ "unit._metadata_flags_test.MetadataFlagsTest",
"unit._metadata_test.MetadataTest",
"unit._reconnect_test.ReconnectTest",
"unit._resource_exhausted_test.ResourceExhaustedTest",
diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel
index dcd6d9fbb2..de33b81e32 100644
--- a/src/python/grpcio_tests/tests/unit/BUILD.bazel
+++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel
@@ -17,6 +17,7 @@ GRPCIO_TESTS_UNIT = [
"_interceptor_test.py",
"_invalid_metadata_test.py",
"_invocation_defects_test.py",
+ "_logging_test.py",
"_metadata_code_details_test.py",
"_metadata_test.py",
# TODO: Issue 16336
diff --git a/src/python/grpcio_tests/tests/unit/_api_test.py b/src/python/grpcio_tests/tests/unit/_api_test.py
index f6245be77d..38072861a4 100644
--- a/src/python/grpcio_tests/tests/unit/_api_test.py
+++ b/src/python/grpcio_tests/tests/unit/_api_test.py
@@ -14,6 +14,7 @@
"""Test of gRPC Python's application-layer API."""
import unittest
+import logging
import six
@@ -102,4 +103,5 @@ class ChannelTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_auth_context_test.py b/src/python/grpcio_tests/tests/unit/_auth_context_test.py
index d174051070..b1b5bbdcab 100644
--- a/src/python/grpcio_tests/tests/unit/_auth_context_test.py
+++ b/src/python/grpcio_tests/tests/unit/_auth_context_test.py
@@ -15,6 +15,7 @@
import pickle
import unittest
+import logging
import grpc
from grpc import _channel
@@ -187,4 +188,5 @@ class AuthContextTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_auth_test.py b/src/python/grpcio_tests/tests/unit/_auth_test.py
index e2cb938936..d9df2add4f 100644
--- a/src/python/grpcio_tests/tests/unit/_auth_test.py
+++ b/src/python/grpcio_tests/tests/unit/_auth_test.py
@@ -16,6 +16,7 @@
import collections
import threading
import unittest
+import logging
from grpc import _auth
@@ -77,4 +78,5 @@ class AccessTokenAuthMetadataPluginTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_channel_args_test.py b/src/python/grpcio_tests/tests/unit/_channel_args_test.py
index dd1d2969a2..228c0e4c16 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_args_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_args_test.py
@@ -15,6 +15,7 @@
from concurrent import futures
import unittest
+import logging
import grpc
@@ -62,4 +63,5 @@ class ChannelArgsTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_channel_close_test.py b/src/python/grpcio_tests/tests/unit/_channel_close_test.py
index af3a9ee1ee..82fa165710 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_close_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_close_test.py
@@ -13,6 +13,7 @@
# limitations under the License.
"""Tests server and client side compression."""
+import logging
import threading
import time
import unittest
@@ -182,4 +183,5 @@ class ChannelCloseTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
index f9eb0011dc..727fb7d65f 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
@@ -13,6 +13,7 @@
# limitations under the License.
"""Tests of grpc._channel.Channel connectivity."""
+import logging
import threading
import time
import unittest
@@ -142,4 +143,5 @@ class ChannelConnectivityTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
index 30b486079c..345460ef40 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
@@ -15,6 +15,7 @@
import threading
import unittest
+import logging
import grpc
from tests.unit.framework.common import test_constants
@@ -85,4 +86,5 @@ class ChannelReadyFutureTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py
index 0b11f03adf..876d8e827e 100644
--- a/src/python/grpcio_tests/tests/unit/_compression_test.py
+++ b/src/python/grpcio_tests/tests/unit/_compression_test.py
@@ -15,6 +15,7 @@
import unittest
+import logging
import grpc
from grpc import _grpcio_metadata
@@ -117,4 +118,5 @@ class CompressionTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_credentials_test.py b/src/python/grpcio_tests/tests/unit/_credentials_test.py
index f487fe66a2..187a6f0388 100644
--- a/src/python/grpcio_tests/tests/unit/_credentials_test.py
+++ b/src/python/grpcio_tests/tests/unit/_credentials_test.py
@@ -14,6 +14,8 @@
"""Tests of credentials."""
import unittest
+import logging
+import six
import grpc
@@ -52,6 +54,17 @@ class CredentialsTest(unittest.TestCase):
self.assertIsInstance(channel_first_second_and_third,
grpc.ChannelCredentials)
+ @unittest.skipIf(six.PY2, 'only invalid in Python3')
+ def test_invalid_string_certificate(self):
+ self.assertRaises(
+ TypeError,
+ grpc.ssl_channel_credentials,
+ root_certificates='A Certificate',
+ private_key=None,
+ certificate_chain=None,
+ )
+
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_empty_message_test.py b/src/python/grpcio_tests/tests/unit/_empty_message_test.py
index c55ef61c13..3e8393b53c 100644
--- a/src/python/grpcio_tests/tests/unit/_empty_message_test.py
+++ b/src/python/grpcio_tests/tests/unit/_empty_message_test.py
@@ -13,6 +13,7 @@
# limitations under the License.
import unittest
+import logging
import grpc
@@ -118,4 +119,5 @@ class EmptyMessageTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py b/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py
new file mode 100644
index 0000000000..6c551df3ec
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py
@@ -0,0 +1,86 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests 'utf-8' encoded error message."""
+
+import unittest
+import weakref
+
+import grpc
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+
+_UNICODE_ERROR_MESSAGES = [
+ b'\xe2\x80\x9d'.decode('utf-8'),
+ b'abc\x80\xd0\xaf'.decode('latin-1'),
+ b'\xc3\xa9'.decode('utf-8'),
+]
+
+_REQUEST = b'\x00\x00\x00'
+_RESPONSE = b'\x00\x00\x00'
+
+_UNARY_UNARY = '/test/UnaryUnary'
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+ def __init__(self, request_streaming=None, response_streaming=None):
+ self.request_streaming = request_streaming
+ self.response_streaming = response_streaming
+ self.request_deserializer = None
+ self.response_serializer = None
+ self.unary_stream = None
+ self.stream_unary = None
+ self.stream_stream = None
+
+ def unary_unary(self, request, servicer_context):
+ servicer_context.set_code(grpc.StatusCode.UNKNOWN)
+ servicer_context.set_details(request.decode('utf-8'))
+ return _RESPONSE
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def __init__(self, test):
+ self._test = test
+
+ def service(self, handler_call_details):
+ return _MethodHandler()
+
+
+class ErrorMessageEncodingTest(unittest.TestCase):
+
+ def setUp(self):
+ self._server = test_common.test_server()
+ self._server.add_generic_rpc_handlers((_GenericHandler(
+ weakref.proxy(self)),))
+ port = self._server.add_insecure_port('[::]:0')
+ self._server.start()
+ self._channel = grpc.insecure_channel('localhost:%d' % port)
+
+ def tearDown(self):
+ self._server.stop(0)
+
+ def testMessageEncoding(self):
+ for message in _UNICODE_ERROR_MESSAGES:
+ multi_callable = self._channel.unary_unary(_UNARY_UNARY)
+ with self.assertRaises(grpc.RpcError) as cm:
+ multi_callable(message.encode('utf-8'))
+
+ self.assertEqual(cm.exception.code(), grpc.StatusCode.UNKNOWN)
+ self.assertEqual(cm.exception.details(), message)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
index 0a0239a63d..d1263c2c56 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
@@ -16,6 +16,7 @@
import argparse
import threading
import time
+import logging
import grpc
@@ -86,7 +87,7 @@ def hang_stream_stream(request_iterator, servicer_context):
def hang_partial_stream_stream(request_iterator, servicer_context):
for _ in range(test_constants.STREAM_LENGTH // 2):
- yield next(request_iterator)
+ yield next(request_iterator) #pylint: disable=stop-iteration-return
time.sleep(WAIT_TIME)
@@ -161,6 +162,7 @@ def infinite_request_iterator():
if __name__ == '__main__':
+ logging.basicConfig()
parser = argparse.ArgumentParser()
parser.add_argument('scenario', type=str)
parser.add_argument(
diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py
index f40f3ae07c..5226537579 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_test.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_test.py
@@ -26,6 +26,7 @@ import sys
import threading
import time
import unittest
+import logging
from tests.unit import _exit_scenarios
@@ -187,4 +188,5 @@ class ExitTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_interceptor_test.py b/src/python/grpcio_tests/tests/unit/_interceptor_test.py
index 3d547b71cd..99db0ac58b 100644
--- a/src/python/grpcio_tests/tests/unit/_interceptor_test.py
+++ b/src/python/grpcio_tests/tests/unit/_interceptor_test.py
@@ -17,6 +17,7 @@ import collections
import itertools
import threading
import unittest
+import logging
from concurrent import futures
import grpc
@@ -598,4 +599,5 @@ class InterceptorTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
index f153089a24..0ff49490d5 100644
--- a/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
+++ b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
@@ -14,6 +14,7 @@
"""Test of RPCs made against gRPC Python's application-layer API."""
import unittest
+import logging
import grpc
@@ -129,6 +130,10 @@ class InvalidMetadataTest(unittest.TestCase):
self._stream_stream(request_iterator, metadata=metadata)
self.assertIn(expected_error_details, str(exception_context.exception))
+ def testInvalidMetadata(self):
+ self.assertRaises(TypeError, self._unary_unary, b'', metadata=42)
+
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
index 93a5fdf9ff..00949e2236 100644
--- a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
+++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
@@ -15,6 +15,7 @@
import itertools
import threading
import unittest
+import logging
import grpc
@@ -271,4 +272,5 @@ class InvocationDefectsTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_logging_test.py b/src/python/grpcio_tests/tests/unit/_logging_test.py
new file mode 100644
index 0000000000..631b9de9db
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_logging_test.py
@@ -0,0 +1,80 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Test of gRPC Python's interaction with the python logging module"""
+
+import unittest
+import six
+from six.moves import reload_module
+import logging
+import grpc
+import functools
+import sys
+
+
+def patch_stderr(f):
+
+ @functools.wraps(f)
+ def _impl(*args, **kwargs):
+ old_stderr = sys.stderr
+ sys.stderr = six.StringIO()
+ try:
+ f(*args, **kwargs)
+ finally:
+ sys.stderr = old_stderr
+
+ return _impl
+
+
+def isolated_logging(f):
+
+ @functools.wraps(f)
+ def _impl(*args, **kwargs):
+ reload_module(logging)
+ reload_module(grpc)
+ try:
+ f(*args, **kwargs)
+ finally:
+ reload_module(logging)
+
+ return _impl
+
+
+class LoggingTest(unittest.TestCase):
+
+ @isolated_logging
+ def test_logger_not_occupied(self):
+ self.assertEqual(0, len(logging.getLogger().handlers))
+
+ @patch_stderr
+ @isolated_logging
+ def test_handler_found(self):
+ self.assertEqual(0, len(sys.stderr.getvalue()))
+
+ @isolated_logging
+ def test_can_configure_logger(self):
+ intended_stream = six.StringIO()
+ logging.basicConfig(stream=intended_stream)
+ self.assertEqual(1, len(logging.getLogger().handlers))
+ self.assertIs(logging.getLogger().handlers[0].stream, intended_stream)
+
+ @isolated_logging
+ def test_grpc_logger(self):
+ self.assertIn("grpc", logging.Logger.manager.loggerDict)
+ root_logger = logging.getLogger("grpc")
+ self.assertEqual(1, len(root_logger.handlers))
+ self.assertIsInstance(root_logger.handlers[0], logging.NullHandler)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py b/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py
index ca10bd4dab..0dafab827a 100644
--- a/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py
+++ b/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py
@@ -15,6 +15,7 @@
import threading
import unittest
+import logging
import grpc
@@ -656,4 +657,5 @@ class MetadataCodeDetailsTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py
new file mode 100644
index 0000000000..2d352e99d4
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py
@@ -0,0 +1,251 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests metadata flags feature by testing wait-for-ready semantics"""
+
+import time
+import weakref
+import unittest
+import threading
+import socket
+from six.moves import queue
+
+import grpc
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+_REQUEST = b'\x00\x00\x00'
+_RESPONSE = b'\x00\x00\x00'
+
+
+def handle_unary_unary(test, request, servicer_context):
+ return _RESPONSE
+
+
+def handle_unary_stream(test, request, servicer_context):
+ for _ in range(test_constants.STREAM_LENGTH):
+ yield _RESPONSE
+
+
+def handle_stream_unary(test, request_iterator, servicer_context):
+ for _ in request_iterator:
+ pass
+ return _RESPONSE
+
+
+def handle_stream_stream(test, request_iterator, servicer_context):
+ for _ in request_iterator:
+ yield _RESPONSE
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+ def __init__(self, test, request_streaming, response_streaming):
+ self.request_streaming = request_streaming
+ self.response_streaming = response_streaming
+ self.request_deserializer = None
+ self.response_serializer = None
+ self.unary_unary = None
+ self.unary_stream = None
+ self.stream_unary = None
+ self.stream_stream = None
+ if self.request_streaming and self.response_streaming:
+ self.stream_stream = lambda req, ctx: handle_stream_stream(test, req, ctx)
+ elif self.request_streaming:
+ self.stream_unary = lambda req, ctx: handle_stream_unary(test, req, ctx)
+ elif self.response_streaming:
+ self.unary_stream = lambda req, ctx: handle_unary_stream(test, req, ctx)
+ else:
+ self.unary_unary = lambda req, ctx: handle_unary_unary(test, req, ctx)
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def __init__(self, test):
+ self._test = test
+
+ def service(self, handler_call_details):
+ if handler_call_details.method == _UNARY_UNARY:
+ return _MethodHandler(self._test, False, False)
+ elif handler_call_details.method == _UNARY_STREAM:
+ return _MethodHandler(self._test, False, True)
+ elif handler_call_details.method == _STREAM_UNARY:
+ return _MethodHandler(self._test, True, False)
+ elif handler_call_details.method == _STREAM_STREAM:
+ return _MethodHandler(self._test, True, True)
+ else:
+ return None
+
+
+def get_free_loopback_tcp_port():
+ tcp = socket.socket(socket.AF_INET6)
+ tcp.bind(('', 0))
+ address_tuple = tcp.getsockname()
+ return tcp, "[::1]:%s" % (address_tuple[1])
+
+
+def create_dummy_channel():
+ """Creating dummy channels is a workaround for retries"""
+ _, addr = get_free_loopback_tcp_port()
+ return grpc.insecure_channel(addr)
+
+
+def perform_unary_unary_call(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).__call__(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_unary_unary_with_call(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).with_call(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_unary_unary_future(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).future(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready).result(
+ timeout=test_constants.LONG_TIMEOUT)
+
+
+def perform_unary_stream_call(channel, wait_for_ready=None):
+ response_iterator = channel.unary_stream(_UNARY_STREAM).__call__(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+ for _ in response_iterator:
+ pass
+
+
+def perform_stream_unary_call(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).__call__(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_stream_unary_with_call(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).with_call(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_stream_unary_future(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).future(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready).result(
+ timeout=test_constants.LONG_TIMEOUT)
+
+
+def perform_stream_stream_call(channel, wait_for_ready=None):
+ response_iterator = channel.stream_stream(_STREAM_STREAM).__call__(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+ for _ in response_iterator:
+ pass
+
+
+_ALL_CALL_CASES = [
+ perform_unary_unary_call, perform_unary_unary_with_call,
+ perform_unary_unary_future, perform_unary_stream_call,
+ perform_stream_unary_call, perform_stream_unary_with_call,
+ perform_stream_unary_future, perform_stream_stream_call
+]
+
+
+class MetadataFlagsTest(unittest.TestCase):
+
+ def check_connection_does_failfast(self, fn, channel, wait_for_ready=None):
+ try:
+ fn(channel, wait_for_ready)
+ self.fail("The Call should fail")
+ except BaseException as e: # pylint: disable=broad-except
+ self.assertIn('StatusCode.UNAVAILABLE', str(e))
+
+ def test_call_wait_for_ready_default(self):
+ for perform_call in _ALL_CALL_CASES:
+ self.check_connection_does_failfast(perform_call,
+ create_dummy_channel())
+
+ def test_call_wait_for_ready_disabled(self):
+ for perform_call in _ALL_CALL_CASES:
+ self.check_connection_does_failfast(
+ perform_call, create_dummy_channel(), wait_for_ready=False)
+
+ def test_call_wait_for_ready_enabled(self):
+ # To test the wait mechanism, Python thread is required to make
+ # client set up first without handling them case by case.
+ # Also, Python thread don't pass the unhandled exceptions to
+ # main thread. So, it need another method to store the
+ # exceptions and raise them again in main thread.
+ unhandled_exceptions = queue.Queue()
+ tcp, addr = get_free_loopback_tcp_port()
+ wg = test_common.WaitGroup(len(_ALL_CALL_CASES))
+
+ def wait_for_transient_failure(channel_connectivity):
+ if channel_connectivity == grpc.ChannelConnectivity.TRANSIENT_FAILURE:
+ wg.done()
+
+ def test_call(perform_call):
+ try:
+ channel = grpc.insecure_channel(addr)
+ channel.subscribe(wait_for_transient_failure)
+ perform_call(channel, wait_for_ready=True)
+ except BaseException as e: # pylint: disable=broad-except
+ # If the call failed, the thread would be destroyed. The channel
+ # object can be collected before calling the callback, which
+ # will result in a deadlock.
+ wg.done()
+ unhandled_exceptions.put(e, True)
+
+ test_threads = []
+ for perform_call in _ALL_CALL_CASES:
+ test_thread = threading.Thread(
+ target=test_call, args=(perform_call,))
+ test_thread.exception = None
+ test_thread.start()
+ test_threads.append(test_thread)
+
+ # Start the server after the connections are waiting
+ wg.wait()
+ tcp.close()
+ server = test_common.test_server()
+ server.add_generic_rpc_handlers((_GenericHandler(weakref.proxy(self)),))
+ server.add_insecure_port(addr)
+ server.start()
+
+ for test_thread in test_threads:
+ test_thread.join()
+
+ # Stop the server to make test end properly
+ server.stop(0)
+
+ if not unhandled_exceptions.empty():
+ raise unhandled_exceptions.get(True)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py
index 5908421011..777ab683e3 100644
--- a/src/python/grpcio_tests/tests/unit/_metadata_test.py
+++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py
@@ -15,6 +15,7 @@
import unittest
import weakref
+import logging
import grpc
from grpc import _channel
@@ -237,4 +238,5 @@ class MetadataTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py
index a708d8d862..f6d4fcbd0a 100644
--- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py
+++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py
@@ -15,6 +15,7 @@
import socket
import time
+import logging
import unittest
import grpc
@@ -100,4 +101,5 @@ class ReconnectTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py b/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py
index df4b129018..4fead8fcd5 100644
--- a/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py
+++ b/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py
@@ -15,6 +15,7 @@
import threading
import unittest
+import logging
import grpc
from grpc import _channel
@@ -253,4 +254,5 @@ class ResourceExhaustedTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_rpc_test.py b/src/python/grpcio_tests/tests/unit/_rpc_test.py
index 34e7831a98..a768d6c7c1 100644
--- a/src/python/grpcio_tests/tests/unit/_rpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_rpc_test.py
@@ -16,6 +16,7 @@
import itertools
import threading
import unittest
+import logging
from concurrent import futures
import grpc
@@ -846,4 +847,5 @@ class RPCTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
index 0d78034b7b..9e4bd61816 100644
--- a/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
+++ b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
@@ -35,6 +35,7 @@ import os
import six
import threading
import unittest
+import logging
from concurrent import futures
@@ -69,18 +70,11 @@ SERVER_CERT_CHAIN_2_PEM = (resources.cert_hier_2_server_1_cert() +
Call = collections.namedtuple('Call', ['did_raise', 'returned_cert_config'])
-def _create_client_stub(
- port,
- expect_success,
- root_certificates=None,
- private_key=None,
- certificate_chain=None,
-):
- channel = grpc.secure_channel('localhost:{}'.format(port),
- grpc.ssl_channel_credentials(
- root_certificates=root_certificates,
- private_key=private_key,
- certificate_chain=certificate_chain))
+def _create_channel(port, credentials):
+ return grpc.secure_channel('localhost:{}'.format(port), credentials)
+
+
+def _create_client_stub(channel, expect_success):
if expect_success:
# per Nathaniel: there's some robustness issue if we start
# using a channel without waiting for it to be actually ready
@@ -175,14 +169,13 @@ class _ServerSSLCertReloadTest(
root_certificates=None,
private_key=None,
certificate_chain=None):
- client_stub = _create_client_stub(
- self.port,
- expect_success,
+ credentials = grpc.ssl_channel_credentials(
root_certificates=root_certificates,
private_key=private_key,
certificate_chain=certificate_chain)
- self._perform_rpc(client_stub, expect_success)
- del client_stub
+ with _create_channel(self.port, credentials) as client_channel:
+ client_stub = _create_client_stub(client_channel, expect_success)
+ self._perform_rpc(client_stub, expect_success)
def _test(self):
# things should work...
@@ -258,12 +251,13 @@ class _ServerSSLCertReloadTest(
# now create the "persistent" clients
self.cert_config_fetcher.reset()
self.cert_config_fetcher.configure(False, None)
- persistent_client_stub_A = _create_client_stub(
+ channel_A = _create_channel(
self.port,
- True,
- root_certificates=CA_1_PEM,
- private_key=CLIENT_KEY_2_PEM,
- certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+ grpc.ssl_channel_credentials(
+ root_certificates=CA_1_PEM,
+ private_key=CLIENT_KEY_2_PEM,
+ certificate_chain=CLIENT_CERT_CHAIN_2_PEM))
+ persistent_client_stub_A = _create_client_stub(channel_A, True)
self._perform_rpc(persistent_client_stub_A, True)
actual_calls = self.cert_config_fetcher.getCalls()
self.assertEqual(len(actual_calls), 1)
@@ -272,12 +266,13 @@ class _ServerSSLCertReloadTest(
self.cert_config_fetcher.reset()
self.cert_config_fetcher.configure(False, None)
- persistent_client_stub_B = _create_client_stub(
+ channel_B = _create_channel(
self.port,
- True,
- root_certificates=CA_1_PEM,
- private_key=CLIENT_KEY_2_PEM,
- certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+ grpc.ssl_channel_credentials(
+ root_certificates=CA_1_PEM,
+ private_key=CLIENT_KEY_2_PEM,
+ certificate_chain=CLIENT_CERT_CHAIN_2_PEM))
+ persistent_client_stub_B = _create_client_stub(channel_B, True)
self._perform_rpc(persistent_client_stub_B, True)
actual_calls = self.cert_config_fetcher.getCalls()
self.assertEqual(len(actual_calls), 1)
@@ -358,6 +353,9 @@ class _ServerSSLCertReloadTest(
actual_calls = self.cert_config_fetcher.getCalls()
self.assertEqual(len(actual_calls), 0)
+ channel_A.close()
+ channel_B.close()
+
class ServerSSLCertConfigFetcherParamsChecks(unittest.TestCase):
@@ -518,4 +516,5 @@ class ServerSSLCertReloadTestCertConfigReuse(_ServerSSLCertReloadTest):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_server_test.py b/src/python/grpcio_tests/tests/unit/_server_test.py
index acf4a17921..2c8205f365 100644
--- a/src/python/grpcio_tests/tests/unit/_server_test.py
+++ b/src/python/grpcio_tests/tests/unit/_server_test.py
@@ -14,6 +14,7 @@
from concurrent import futures
import unittest
+import logging
import grpc
@@ -49,4 +50,5 @@ class ServerTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_session_cache_test.py b/src/python/grpcio_tests/tests/unit/_session_cache_test.py
index b4e4670fa7..9223a6da03 100644
--- a/src/python/grpcio_tests/tests/unit/_session_cache_test.py
+++ b/src/python/grpcio_tests/tests/unit/_session_cache_test.py
@@ -15,6 +15,7 @@
import pickle
import unittest
+import logging
import grpc
from grpc import _channel
@@ -142,4 +143,5 @@ class SSLSessionCacheTest(unittest.TestCase):
if __name__ == '__main__':
+ logging.basicConfig()
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel b/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel
deleted file mode 100644
index d3e0fe20eb..0000000000
--- a/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel
+++ /dev/null
@@ -1,75 +0,0 @@
-load("@grpc_python_dependencies//:requirements.bzl", "requirement")
-
-package(default_visibility = ["//visibility:public"])
-
-py_library(
- name = "test_utilities",
- srcs = ["test_utilities.py"],
- deps = [
- "//src/python/grpcio/grpc:grpcio",
- ],
-)
-
-py_test(
- name = "_beta_features_test",
- srcs = ["_beta_features_test.py"],
- main = "_beta_features_test.py",
- size = "small",
- deps = [
- "//src/python/grpcio/grpc:grpcio",
- "//src/python/grpcio_tests/tests/unit:resources",
- "//src/python/grpcio_tests/tests/unit/framework/common",
- ":test_utilities",
- ],
- imports=["../../../",],
-)
-
-py_test(
- name = "_connectivity_channel_test",
- srcs = ["_connectivity_channel_test.py"],
- main = "_connectivity_channel_test.py",
- size = "small",
- deps = [
- "//src/python/grpcio/grpc:grpcio",
- ],
-)
-
-# TODO(ghostwriternr): To be added later.
-#py_test(
-# name = "_implementations_test",
-# srcs = ["_implementations_test.py"],
-# main = "_implementations_test.py",
-# size = "small",
-# deps = [
-# "//src/python/grpcio/grpc:grpcio",
-# "//src/python/grpcio_tests/tests/unit:resources",
-# requirement('oauth2client'),
-# ],
-# imports=["../../../",],
-#)
-
-py_test(
- name = "_not_found_test",
- srcs = ["_not_found_test.py"],
- main = "_not_found_test.py",
- size = "small",
- deps = [
- "//src/python/grpcio/grpc:grpcio",
- "//src/python/grpcio_tests/tests/unit/framework/common",
- ],
- imports=["../../../",],
-)
-
-py_test(
- name = "_utilities_test",
- srcs = ["_utilities_test.py"],
- main = "_utilities_test.py",
- size = "small",
- deps = [
- "//src/python/grpcio/grpc:grpcio",
- "//src/python/grpcio_tests/tests/unit/framework/common",
- ],
- imports=["../../../",],
-)
-
-
diff --git a/src/python/grpcio_tests/tests/unit/resources.py b/src/python/grpcio_tests/tests/unit/resources.py
index 51a8979f58..6efd870fc8 100644
--- a/src/python/grpcio_tests/tests/unit/resources.py
+++ b/src/python/grpcio_tests/tests/unit/resources.py
@@ -14,8 +14,7 @@
"""Constants and functions for data used in testing."""
import os
-
-import pkg_resources
+import pkgutil
_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem'
_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
@@ -23,94 +22,92 @@ _CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
def test_root_certificates():
- return pkg_resources.resource_string(__name__,
- _ROOT_CERTIFICATES_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
def private_key():
- return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _PRIVATE_KEY_RESOURCE_PATH)
def certificate_chain():
- return pkg_resources.resource_string(__name__,
- _CERTIFICATE_CHAIN_RESOURCE_PATH)
+ return pkgutil.get_data(__name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
def cert_hier_1_root_ca_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__, 'credentials/certificate_hierarchy_1/certs/ca.cert.pem')
def cert_hier_1_intermediate_ca_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem'
)
def cert_hier_1_client_1_key():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_1/intermediate/private/client.key.pem'
)
def cert_hier_1_client_1_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem'
)
def cert_hier_1_server_1_key():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem'
)
def cert_hier_1_server_1_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem'
)
def cert_hier_2_root_ca_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__, 'credentials/certificate_hierarchy_2/certs/ca.cert.pem')
def cert_hier_2_intermediate_ca_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem'
)
def cert_hier_2_client_1_key():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_2/intermediate/private/client.key.pem'
)
def cert_hier_2_client_1_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem'
)
def cert_hier_2_server_1_key():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem'
)
def cert_hier_2_server_1_cert():
- return pkg_resources.resource_string(
+ return pkgutil.get_data(
__name__,
'credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem'
)
diff --git a/src/python/grpcio_tests/tests/unit/test_common.py b/src/python/grpcio_tests/tests/unit/test_common.py
index 61717ae135..bc3b24862d 100644
--- a/src/python/grpcio_tests/tests/unit/test_common.py
+++ b/src/python/grpcio_tests/tests/unit/test_common.py
@@ -14,6 +14,7 @@
"""Common code used throughout tests of gRPC."""
import collections
+import threading
from concurrent import futures
import grpc
@@ -107,3 +108,28 @@ def test_server(max_workers=10):
return grpc.server(
futures.ThreadPoolExecutor(max_workers=max_workers),
options=(('grpc.so_reuseport', 0),))
+
+
+class WaitGroup(object):
+
+ def __init__(self, n=0):
+ self.count = n
+ self.cv = threading.Condition()
+
+ def add(self, n):
+ self.cv.acquire()
+ self.count += n
+ self.cv.release()
+
+ def done(self):
+ self.cv.acquire()
+ self.count -= 1
+ if self.count == 0:
+ self.cv.notify_all()
+ self.cv.release()
+
+ def wait(self):
+ self.cv.acquire()
+ while self.count > 0:
+ self.cv.wait()
+ self.cv.release()
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 0e192b6201..18245e9107 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -98,6 +98,7 @@ grpc_resource_quota_set_max_threads_type grpc_resource_quota_set_max_threads_imp
grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import;
grpc_channelz_get_servers_type grpc_channelz_get_servers_import;
+grpc_channelz_get_server_type grpc_channelz_get_server_import;
grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import;
grpc_channelz_get_channel_type grpc_channelz_get_channel_import;
grpc_channelz_get_subchannel_type grpc_channelz_get_subchannel_import;
@@ -355,6 +356,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_resource_quota_arg_vtable_import = (grpc_resource_quota_arg_vtable_type) GetProcAddress(library, "grpc_resource_quota_arg_vtable");
grpc_channelz_get_top_channels_import = (grpc_channelz_get_top_channels_type) GetProcAddress(library, "grpc_channelz_get_top_channels");
grpc_channelz_get_servers_import = (grpc_channelz_get_servers_type) GetProcAddress(library, "grpc_channelz_get_servers");
+ grpc_channelz_get_server_import = (grpc_channelz_get_server_type) GetProcAddress(library, "grpc_channelz_get_server");
grpc_channelz_get_server_sockets_import = (grpc_channelz_get_server_sockets_type) GetProcAddress(library, "grpc_channelz_get_server_sockets");
grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel");
grpc_channelz_get_subchannel_import = (grpc_channelz_get_subchannel_type) GetProcAddress(library, "grpc_channelz_get_subchannel");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index e075db89e8..56d222c7ec 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -269,6 +269,9 @@ extern grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import
typedef char*(*grpc_channelz_get_servers_type)(intptr_t start_server_id);
extern grpc_channelz_get_servers_type grpc_channelz_get_servers_import;
#define grpc_channelz_get_servers grpc_channelz_get_servers_import
+typedef char*(*grpc_channelz_get_server_type)(intptr_t server_id);
+extern grpc_channelz_get_server_type grpc_channelz_get_server_import;
+#define grpc_channelz_get_server grpc_channelz_get_server_import
typedef char*(*grpc_channelz_get_server_sockets_type)(intptr_t server_id, intptr_t start_socket_id);
extern grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import;
#define grpc_channelz_get_server_sockets grpc_channelz_get_server_sockets_import
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 4764217406..169a62f11d 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -95,7 +95,7 @@ module GRPC
rpc_descs[name] = RpcDesc.new(name, input, output,
marshal_class_method,
unmarshal_class_method)
- define_method(GenericService.underscore(name.to_s).to_sym) do |_, _|
+ define_method(GenericService.underscore(name.to_s).to_sym) do |*|
fail GRPC::BadStatus.new_status_exception(
GRPC::Core::StatusCodes::UNIMPLEMENTED)
end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 243d566645..a4ed052d85 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '1.17.0.dev'
+ VERSION = '1.18.0.dev'
end
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index c492455d8f..7ad68409dd 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -14,7 +14,6 @@
require 'grpc'
require 'grpc/health/v1/health_services_pb'
-require 'thread'
module Grpc
# Health contains classes and modules that support providing a health check
@@ -37,9 +36,9 @@ module Grpc
@status_mutex.synchronize do
status = @statuses["#{req.service}"]
end
- if status.nil?
+ if status.nil?
fail GRPC::BadStatus.new_status_exception(StatusCodes::NOT_FOUND)
- end
+ end
HealthCheckResponse.new(status: status)
end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 44a6134086..924d747a79 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -342,6 +342,28 @@ describe GRPC::RpcServer do
t.join
end
+ it 'should return UNIMPLEMENTED on unimplemented ' \
+ 'methods for client_streamer', server: true do
+ @srv.handle(EchoService)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ blk = proc do
+ stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts)
+ requests = [EchoMsg.new, EchoMsg.new]
+ stub.a_client_streaming_rpc_unimplemented(requests)
+ end
+
+ begin
+ expect(&blk).to raise_error do |error|
+ expect(error).to be_a(GRPC::BadStatus)
+ expect(error.code).to eq(GRPC::Core::StatusCodes::UNIMPLEMENTED)
+ end
+ ensure
+ @srv.stop # should be call not to crash
+ t.join
+ end
+ end
+
it 'should handle multiple sequential requests', server: true do
@srv.handle(EchoService)
t = Thread.new { @srv.run }
diff --git a/src/ruby/spec/support/services.rb b/src/ruby/spec/support/services.rb
index 6e693f1cde..438459dfd7 100644
--- a/src/ruby/spec/support/services.rb
+++ b/src/ruby/spec/support/services.rb
@@ -33,6 +33,7 @@ class EchoService
rpc :a_client_streaming_rpc, stream(EchoMsg), EchoMsg
rpc :a_server_streaming_rpc, EchoMsg, stream(EchoMsg)
rpc :a_bidi_rpc, stream(EchoMsg), stream(EchoMsg)
+ rpc :a_client_streaming_rpc_unimplemented, stream(EchoMsg), EchoMsg
attr_reader :received_md
def initialize(**kw)
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 92e85eb882..389fb70684 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
module GRPC
module Tools
- VERSION = '1.17.0.dev'
+ VERSION = '1.18.0.dev'
end
end
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 0b67416d3e..8bb06176bf 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -1370,7 +1370,7 @@
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]})-dll.a $(prefix)/lib/lib${lib.name}.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
+ $(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major}
$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so
endif
% endif
diff --git a/templates/config.m4.template b/templates/config.m4.template
index 19f9904911..18378cfc34 100644
--- a/templates/config.m4.template
+++ b/templates/config.m4.template
@@ -45,7 +45,8 @@
% endfor
, $ext_shared, , -fvisibility=hidden ${"\\"}
-DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN ${"\\"}
- -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0)
+ -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0 ${"\\"}
+ -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1)
PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
<%
diff --git a/templates/gRPC-C++.podspec.template b/templates/gRPC-C++.podspec.template
index cff252b3a9..94d5a4fb09 100644
--- a/templates/gRPC-C++.podspec.template
+++ b/templates/gRPC-C++.podspec.template
@@ -127,12 +127,20 @@
def ruby_multiline_list(files, indent):
return (',\n' + indent*' ').join('\'%s\'' % f for f in files)
+
+ def modify_podspec_version_string(pod_version, grpc_version):
+ # Append -preX when it is a pre-release
+ if len(str(grpc_version).split('-')) > 1:
+ return pod_version + '-' + str(grpc_version).split('-')[-1]
+ else:
+ return pod_version
+
%>
Pod::Spec.new do |s|
s.name = 'gRPC-C++'
# TODO (mxyan): use version that match gRPC version when pod is stabilized
# version = '${settings.version}'
- version = '0.0.3'
+ version = '${modify_podspec_version_string('0.0.6', settings.version)}'
s.version = version
s.summary = 'gRPC C++ library'
s.homepage = 'https://grpc.io'
@@ -177,6 +185,9 @@
s.default_subspecs = 'Interface', 'Implementation'
+ # Certificates, to be able to establish TLS connections:
+ s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
+
s.header_mappings_dir = 'include/grpcpp'
s.subspec 'Interface' do |ss|
diff --git a/templates/src/python/grpcio_channelz/grpc_version.py.template b/templates/src/python/grpcio_channelz/grpc_version.py.template
new file mode 100644
index 0000000000..75d510cd17
--- /dev/null
+++ b/templates/src/python/grpcio_channelz/grpc_version.py.template
@@ -0,0 +1,19 @@
+%YAML 1.2
+--- |
+ # Copyright 2018 The gRPC Authors
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
+
+ VERSION = '${settings.python_version.pep440()}'
diff --git a/templates/tools/dockerfile/bazel.include b/templates/tools/dockerfile/bazel.include
index ee4f9556af..c7714f5663 100644
--- a/templates/tools/dockerfile/bazel.include
+++ b/templates/tools/dockerfile/bazel.include
@@ -1,5 +1,6 @@
#========================
# Bazel installation
-RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
-RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
-RUN apt-get -y update && apt-get -y install bazel=0.15.0 && apt-get clean
+
+RUN apt-get update && apt-get install -y wget && apt-get clean
+RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
+RUN chmod 755 /usr/local/bin/bazel
diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include
index 7ed0074867..fdede9e840 100644
--- a/templates/tools/dockerfile/csharp_deps.include
+++ b/templates/tools/dockerfile/csharp_deps.include
@@ -1,24 +1,15 @@
#================
# C# dependencies
-# Update to a newer version of mono
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian jessie main" | tee /etc/apt/sources.list.d/mono-official.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y ${'\\'}
+# cmake >=3.6 needed to build grpc_csharp_ext
+RUN apt-get update && apt-get install -y cmake && apt-get clean
+
+# Install mono
+RUN apt-get update && apt-get install -y apt-transport-https dirmngr && apt-get clean
+RUN apt-key adv --no-tty --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb https://download.mono-project.com/repo/debian stable-stretch main" | tee /etc/apt/sources.list.d/mono-official-stable.list
+RUN apt-get update && apt-get install -y ${'\\'}
mono-devel ${'\\'}
ca-certificates-mono ${'\\'}
nuget ${'\\'}
&& apt-get clean
-
-RUN nuget update -self
-
-#=================
-# Use cmake 3.6 from jessie-backports
-# needed to build grpc_csharp_ext with cmake
-
-RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
diff --git a/templates/tools/dockerfile/csharp_dotnetcli_deps.include b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
index bc88d2bfa3..f333592640 100644
--- a/templates/tools/dockerfile/csharp_dotnetcli_deps.include
+++ b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
@@ -1,12 +1,20 @@
-# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
-RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003131
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
-RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
-# dotnet-dev-1.0.1
-RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
-RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
-RUN ln -s /opt/dotnet/dotnet /usr/local/bin
+# Install dotnet SDK
+ENV DOTNET_SDK_VERSION 2.1.500
+RUN curl -sSL -o dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz ${'\\'}
+ && mkdir -p /usr/share/dotnet ${'\\'}
+ && tar -zxf dotnet.tar.gz -C /usr/share/dotnet ${'\\'}
+ && rm dotnet.tar.gz ${'\\'}
+ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
+
+
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+RUN curl -sSL -o dotnet_old.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/1.1.10/dotnet-debian.9-x64.1.1.10.tar.gz ${'\\'}
+ && mkdir -p dotnet_old ${'\\'}
+ && tar zxf dotnet_old.tar.gz -C dotnet_old ${'\\'}
+ && cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/ ${'\\'}
+ && rm -rf dotnet_old/ dotnet_old.tar.gz
+RUN apt-get update && apt-get install -y libunwind8 && apt-get clean
+
# Trigger the population of the local package cache
ENV NUGET_XMLDOC_MODE skip
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
index a1f1283de0..abf1a3853d 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM debian:jessie
+ FROM debian:stretch
<%include file="../../apt_get_basic.include"/>
<%include file="../../python_deps.include"/>
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template
index a1f1283de0..abf1a3853d 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM debian:jessie
+ FROM debian:stretch
<%include file="../../apt_get_basic.include"/>
<%include file="../../python_deps.include"/>
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
index bf28796de3..f584a2378e 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
@@ -14,15 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM debian:jessie
-
- <%include file="../../apt_get_basic.include"/>
- <%include file="../../python_deps.include"/>
- # Install pip and virtualenv for Python 3.4
- RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
- RUN python3.4 -m pip install virtualenv
+ <%include file="../../python_stretch.include"/>
- <%include file="../../run_tests_addons.include"/>
- # Define the default command.
- CMD ["bash"]
-
+ RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
+ RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
diff --git a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_stretch_x64/Dockerfile.template
index 432f05442c..1526d07fc6 100644
--- a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/csharp_stretch_x64/Dockerfile.template
@@ -1,6 +1,6 @@
%YAML 1.2
--- |
- # Copyright 2015 gRPC authors.
+ # Copyright 2018 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM debian:jessie
+ FROM debian:stretch
<%include file="../../apt_get_basic.include"/>
<%include file="../../gcp_api_libraries.include"/>
diff --git a/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
deleted file mode 100644
index ac687b710f..0000000000
--- a/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
+++ /dev/null
@@ -1,41 +0,0 @@
-%YAML 1.2
---- |
- # Copyright 2016 gRPC authors.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
-
- FROM debian:jessie
-
- <%include file="../../apt_get_basic.include"/>
- <%include file="../../gcp_api_libraries.include"/>
- <%include file="../../csharp_deps.include"/>
- <%include file="../../csharp_dotnetcli_deps.include"/>
- <%include file="../../cxx_deps.include"/>
- <%include file="../../node_deps.include"/>
- <%include file="../../php_deps.include"/>
- <%include file="../../ruby_deps.include"/>
- <%include file="../../python_deps.include"/>
- # Install pip and virtualenv for Python 3.4
- RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
- RUN python3.4 -m pip install virtualenv
-
- # Install coverage for Python test coverage reporting
- RUN pip install coverage
- ENV PATH ~/.local/bin:$PATH
-
- # Install Mako to generate files in grpc/grpc-node
- RUN pip install Mako
-
- <%include file="../../run_tests_addons.include"/>
- # Define the default command.
- CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template
index ff342db493..c3602f6c51 100644
--- a/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template
@@ -18,3 +18,6 @@
RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
+
+ # for Python test coverage reporting
+ RUN pip install coverage
diff --git a/test/core/avl/avl_test.cc b/test/core/avl/avl_test.cc
index 01002fec72..769e67563d 100644
--- a/test/core/avl/avl_test.cc
+++ b/test/core/avl/avl_test.cc
@@ -283,7 +283,7 @@ static void test_stress(int amount_of_stress) {
}
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_get();
test_ll();
diff --git a/test/core/backoff/backoff_test.cc b/test/core/backoff/backoff_test.cc
index 1998a83977..8fd120e042 100644
--- a/test/core/backoff/backoff_test.cc
+++ b/test/core/backoff/backoff_test.cc
@@ -171,7 +171,7 @@ TEST(BackOffTest, JitterBackOff) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc
index 4f5d2a2862..ae1e42a4e0 100644
--- a/test/core/bad_client/bad_client.cc
+++ b/test/core/bad_client/bad_client.cc
@@ -66,7 +66,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
thd_args* a = static_cast<thd_args*>(ts);
grpc_core::ExecCtx exec_ctx;
grpc_server_setup_transport(a->server, transport, nullptr,
- grpc_server_get_channel_args(a->server), 0);
+ grpc_server_get_channel_args(a->server), nullptr);
}
/* Sets the read_done event */
diff --git a/test/core/bad_client/tests/badreq.cc b/test/core/bad_client/tests/badreq.cc
index eeaf4c9974..c560dc5561 100644
--- a/test/core/bad_client/tests/badreq.cc
+++ b/test/core/bad_client/tests/badreq.cc
@@ -39,7 +39,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* invalid content type */
diff --git a/test/core/bad_client/tests/connection_prefix.cc b/test/core/bad_client/tests/connection_prefix.cc
index 4aab234d3e..286a3ccafb 100644
--- a/test/core/bad_client/tests/connection_prefix.cc
+++ b/test/core/bad_client/tests/connection_prefix.cc
@@ -29,7 +29,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr, "X", 0);
diff --git a/test/core/bad_client/tests/duplicate_header.cc b/test/core/bad_client/tests/duplicate_header.cc
index e3cae8b595..dfa6e51811 100644
--- a/test/core/bad_client/tests/duplicate_header.cc
+++ b/test/core/bad_client/tests/duplicate_header.cc
@@ -122,7 +122,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* Verify that sending multiple headers doesn't segfault */
diff --git a/test/core/bad_client/tests/head_of_line_blocking.cc b/test/core/bad_client/tests/head_of_line_blocking.cc
index 427db46446..c856b9b122 100644
--- a/test/core/bad_client/tests/head_of_line_blocking.cc
+++ b/test/core/bad_client/tests/head_of_line_blocking.cc
@@ -109,7 +109,7 @@ static void addbuf(const void* data, size_t len) {
int main(int argc, char** argv) {
int i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
#define NUM_FRAMES 10
diff --git a/test/core/bad_client/tests/headers.cc b/test/core/bad_client/tests/headers.cc
index 2aa1b280ce..02ea759750 100644
--- a/test/core/bad_client/tests/headers.cc
+++ b/test/core/bad_client/tests/headers.cc
@@ -33,7 +33,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* partial http2 header prefixes */
diff --git a/test/core/bad_client/tests/initial_settings_frame.cc b/test/core/bad_client/tests/initial_settings_frame.cc
index 0220000ece..fcbb841331 100644
--- a/test/core/bad_client/tests/initial_settings_frame.cc
+++ b/test/core/bad_client/tests/initial_settings_frame.cc
@@ -32,7 +32,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* various partial prefixes */
diff --git a/test/core/bad_client/tests/large_metadata.cc b/test/core/bad_client/tests/large_metadata.cc
index d534753f53..520a1af0c2 100644
--- a/test/core/bad_client/tests/large_metadata.cc
+++ b/test/core/bad_client/tests/large_metadata.cc
@@ -141,7 +141,7 @@ static void server_verifier_sends_too_much_metadata(grpc_server* server,
int main(int argc, char** argv) {
int i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
// Test sending more metadata than the server will accept.
gpr_strvec headers;
diff --git a/test/core/bad_client/tests/server_registered_method.cc b/test/core/bad_client/tests/server_registered_method.cc
index c2dc9c66af..834142ac1b 100644
--- a/test/core/bad_client/tests/server_registered_method.cc
+++ b/test/core/bad_client/tests/server_registered_method.cc
@@ -76,7 +76,7 @@ static void verifier_fails(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* body generated with
diff --git a/test/core/bad_client/tests/simple_request.cc b/test/core/bad_client/tests/simple_request.cc
index c80fc5cb4a..34049aaaff 100644
--- a/test/core/bad_client/tests/simple_request.cc
+++ b/test/core/bad_client/tests/simple_request.cc
@@ -123,7 +123,7 @@ static void failure_verifier(grpc_server* server, grpc_completion_queue* cq,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* basic request: check that things are working */
diff --git a/test/core/bad_client/tests/unknown_frame.cc b/test/core/bad_client/tests/unknown_frame.cc
index b1b618a43f..9e0cf3f6a9 100644
--- a/test/core/bad_client/tests/unknown_frame.cc
+++ b/test/core/bad_client/tests/unknown_frame.cc
@@ -34,7 +34,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
int main(int argc, char** argv) {
grpc_init();
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* test adding prioritization data */
GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr,
diff --git a/test/core/bad_client/tests/window_overflow.cc b/test/core/bad_client/tests/window_overflow.cc
index b552704e9c..87042a46f2 100644
--- a/test/core/bad_client/tests/window_overflow.cc
+++ b/test/core/bad_client/tests/window_overflow.cc
@@ -71,7 +71,7 @@ int main(int argc, char** argv) {
#define FRAME_SIZE (MESSAGES_PER_FRAME * 5)
#define SEND_SIZE (4 * 1024 * 1024)
#define NUM_FRAMES (SEND_SIZE / FRAME_SIZE + 1)
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
addbuf(PFX_STR, sizeof(PFX_STR) - 1);
diff --git a/test/core/channel/channel_args_test.cc b/test/core/channel/channel_args_test.cc
index 41c62a8f16..087a7679bf 100644
--- a/test/core/channel/channel_args_test.cc
+++ b/test/core/channel/channel_args_test.cc
@@ -231,7 +231,7 @@ static void test_server_create_with_args(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_create();
test_set_compression_algorithm();
diff --git a/test/core/channel/channel_stack_builder_test.cc b/test/core/channel/channel_stack_builder_test.cc
index aad6d6eee9..b5598e63f9 100644
--- a/test/core/channel/channel_stack_builder_test.cc
+++ b/test/core/channel/channel_stack_builder_test.cc
@@ -132,7 +132,7 @@ static void init_plugin(void) {
static void destroy_plugin(void) {}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_register_plugin(init_plugin, destroy_plugin);
grpc_init();
test_channel_stack_builder_filter_replace();
diff --git a/test/core/channel/channel_stack_test.cc b/test/core/channel/channel_stack_test.cc
index 6f0bfa06d2..14726336f9 100644
--- a/test/core/channel/channel_stack_test.cc
+++ b/test/core/channel/channel_stack_test.cc
@@ -147,7 +147,7 @@ static void test_create_channel_stack(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_create_channel_stack();
grpc_shutdown();
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc
index 3d8de79e37..b3c0b36898 100644
--- a/test/core/channel/channel_trace_test.cc
+++ b/test/core/channel/channel_trace_test.cc
@@ -342,7 +342,7 @@ TEST(ChannelTracerTest, TestTotalEviction) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
diff --git a/test/core/channel/channelz_registry_test.cc b/test/core/channel/channelz_registry_test.cc
index fdfc8eec94..ed3d629dc9 100644
--- a/test/core/channel/channelz_registry_test.cc
+++ b/test/core/channel/channelz_registry_test.cc
@@ -195,7 +195,7 @@ TEST_F(ChannelzRegistryTest, TestAddAfterCompaction) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc
index 5f27320512..abd1601ad1 100644
--- a/test/core/channel/channelz_test.cc
+++ b/test/core/channel/channelz_test.cc
@@ -224,6 +224,11 @@ void ValidateServer(ServerNode* server, validate_channel_data_args args) {
grpc::testing::ValidateServerProtoJsonTranslation(json_str);
ValidateCounters(json_str, args);
gpr_free(json_str);
+ // also check that the core API formats this the correct way
+ char* core_api_json_str = grpc_channelz_get_server(server->uuid());
+ grpc::testing::ValidateGetServerResponseProtoJsonTranslation(
+ core_api_json_str);
+ gpr_free(core_api_json_str);
}
grpc_millis GetLastCallStartedMillis(CallCountingHelper* channel) {
@@ -536,7 +541,7 @@ INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
diff --git a/test/core/channel/minimal_stack_is_minimal_test.cc b/test/core/channel/minimal_stack_is_minimal_test.cc
index e5953acedc..bee0bfb41f 100644
--- a/test/core/channel/minimal_stack_is_minimal_test.cc
+++ b/test/core/channel/minimal_stack_is_minimal_test.cc
@@ -56,7 +56,7 @@ static int check_stack(const char* file, int line, const char* transport_name,
#define CHECK_STACK(...) check_stack(__FILE__, __LINE__, __VA_ARGS__)
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
int errors = 0;
diff --git a/test/core/client_channel/parse_address_test.cc b/test/core/client_channel/parse_address_test.cc
index 004549fa62..b77a51a9e4 100644
--- a/test/core/client_channel/parse_address_test.cc
+++ b/test/core/client_channel/parse_address_test.cc
@@ -101,7 +101,7 @@ static void test_grpc_parse_ipv6_invalid(const char* uri_text) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_grpc_parse_unix("unix:/path/name", "/path/name");
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
index eb5a911748..76769b2b64 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
@@ -64,7 +64,7 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout_ms, grpc_combiner* combiner) {
gpr_mu_lock(&g_mu);
GPR_ASSERT(0 == strcmp("test", addr));
grpc_error* error = GRPC_ERROR_NONE;
@@ -145,7 +145,7 @@ static void call_resolver_next_after_locking(grpc_core::Resolver* resolver,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
gpr_mu_init(&g_mu);
diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
index 1a7db40f59..cdbe33dbe7 100644
--- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
@@ -41,7 +41,7 @@ static grpc_ares_request* (*g_default_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner);
+ int query_timeout_ms, grpc_combiner* combiner);
// Counter incremented by test_resolve_address_impl indicating the number of
// times a system-level resolution has happened.
@@ -91,10 +91,10 @@ static grpc_ares_request* test_dns_lookup_ares_locked(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout_ms, grpc_combiner* combiner) {
grpc_ares_request* result = g_default_dns_lookup_ares_locked(
dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs,
- check_grpclb, service_config_json, combiner);
+ check_grpclb, service_config_json, query_timeout_ms, combiner);
++g_resolution_count;
static grpc_millis last_resolution_time = 0;
if (last_resolution_time == 0) {
@@ -262,7 +262,7 @@ static void test_cooldown() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
g_combiner = grpc_combiner_create();
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.cc b/test/core/client_channel/resolvers/dns_resolver_test.cc
index 103b2916c4..571746abe8 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_test.cc
@@ -60,7 +60,7 @@ static void test_fails(grpc_core::ResolverFactory* factory,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
g_combiner = grpc_combiner_create();
diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc
index f6696bf127..6362b95e50 100644
--- a/test/core/client_channel/resolvers/fake_resolver_test.cc
+++ b/test/core/client_channel/resolvers/fake_resolver_test.cc
@@ -213,7 +213,7 @@ static void test_fake_resolver() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_fake_resolver();
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
index b9287c2468..ff7db6046d 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
@@ -84,7 +84,7 @@ static void test_fails(grpc_core::ResolverFactory* factory,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
g_combiner = grpc_combiner_create();
diff --git a/test/core/client_channel/retry_throttle_test.cc b/test/core/client_channel/retry_throttle_test.cc
index c6d5d3ebbb..793e86dc06 100644
--- a/test/core/client_channel/retry_throttle_test.cc
+++ b/test/core/client_channel/retry_throttle_test.cc
@@ -136,7 +136,7 @@ TEST(ServerRetryThrottleMap, Replacement) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/client_channel/uri_fuzzer_test.cc b/test/core/client_channel/uri_fuzzer_test.cc
index ee38453166..a88e2ac5cf 100644
--- a/test/core/client_channel/uri_fuzzer_test.cc
+++ b/test/core/client_channel/uri_fuzzer_test.cc
@@ -23,8 +23,8 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
-#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/uri/uri_parser.h"
bool squelch = true;
bool leak_check = true;
diff --git a/test/core/client_channel/uri_parser_test.cc b/test/core/client_channel/uri_parser_test.cc
index 254bfddfb3..713ec32e5e 100644
--- a/test/core/client_channel/uri_parser_test.cc
+++ b/test/core/client_channel/uri_parser_test.cc
@@ -16,7 +16,7 @@
*
*/
-#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/uri/uri_parser.h"
#include <string.h>
@@ -119,7 +119,7 @@ static void test_query_parts() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_succeeds("http://www.google.com", "http", "www.google.com", "", "", "");
test_succeeds("dns:///foo", "dns", "", "/foo", "", "");
diff --git a/test/core/compression/algorithm_test.cc b/test/core/compression/algorithm_test.cc
index 8989a41989..24fe83774b 100644
--- a/test/core/compression/algorithm_test.cc
+++ b/test/core/compression/algorithm_test.cc
@@ -105,7 +105,7 @@ static void test_algorithm_failure(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_algorithm_mesh();
diff --git a/test/core/compression/message_compress_test.cc b/test/core/compression/message_compress_test.cc
index e3fe825fdf..e2abf2d321 100644
--- a/test/core/compression/message_compress_test.cc
+++ b/test/core/compression/message_compress_test.cc
@@ -292,7 +292,7 @@ int main(int argc, char** argv) {
GRPC_SLICE_SPLIT_IDENTITY,
GRPC_SLICE_SPLIT_ONE_BYTE};
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
for (i = 0; i < GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT; i++) {
diff --git a/test/core/debug/BUILD b/test/core/debug/BUILD
new file mode 100644
index 0000000000..1592472532
--- /dev/null
+++ b/test/core/debug/BUILD
@@ -0,0 +1,34 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package")
+
+grpc_package(name = "test/core/debug")
+
+licenses(["notice"]) # Apache v2
+
+grpc_cc_test(
+ name = "stats_test",
+ srcs = ["stats_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/end2end/bad_server_response_test.cc b/test/core/end2end/bad_server_response_test.cc
index f7396a1684..f8ffb55180 100644
--- a/test/core/end2end/bad_server_response_test.cc
+++ b/test/core/end2end/bad_server_response_test.cc
@@ -302,7 +302,7 @@ static void run_test(const char* response_payload,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
/* status defined in hpack static table */
diff --git a/test/core/end2end/connection_refused_test.cc b/test/core/end2end/connection_refused_test.cc
index 33812ec8e5..4318811b81 100644
--- a/test/core/end2end/connection_refused_test.cc
+++ b/test/core/end2end/connection_refused_test.cc
@@ -142,7 +142,7 @@ static void run_test(bool wait_for_ready, bool use_service_config) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
run_test(false /* wait_for_ready */, false /* use_service_config */);
run_test(true /* wait_for_ready */, false /* use_service_config */);
run_test(true /* wait_for_ready */, true /* use_service_config */);
diff --git a/test/core/end2end/dualstack_socket_test.cc b/test/core/end2end/dualstack_socket_test.cc
index eb1d043fb2..330af8fce0 100644
--- a/test/core/end2end/dualstack_socket_test.cc
+++ b/test/core/end2end/dualstack_socket_test.cc
@@ -303,7 +303,7 @@ int external_dns_works(const char* host) {
int main(int argc, char** argv) {
int do_ipv6 = 1;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
if (!grpc_ipv6_loopback_available()) {
diff --git a/test/core/end2end/fixtures/h2_census.cc b/test/core/end2end/fixtures/h2_census.cc
index 29b1d6d883..60442ddcc7 100644
--- a/test/core/end2end/fixtures/h2_census.cc
+++ b/test/core/end2end/fixtures/h2_census.cc
@@ -118,7 +118,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_compress.cc b/test/core/end2end/fixtures/h2_compress.cc
index 4aaadf715c..04142daf63 100644
--- a/test/core/end2end/fixtures/h2_compress.cc
+++ b/test/core/end2end/fixtures/h2_compress.cc
@@ -118,7 +118,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_fakesec.cc b/test/core/end2end/fixtures/h2_fakesec.cc
index a653d7c477..ad83aab39f 100644
--- a/test/core/end2end/fixtures/h2_fakesec.cc
+++ b/test/core/end2end/fixtures/h2_fakesec.cc
@@ -142,7 +142,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_fd.cc b/test/core/end2end/fixtures/h2_fd.cc
index 52be0f7fd5..5d06bd5f3b 100644
--- a/test/core/end2end/fixtures/h2_fd.cc
+++ b/test/core/end2end/fixtures/h2_fd.cc
@@ -104,7 +104,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_full+pipe.cc b/test/core/end2end/fixtures/h2_full+pipe.cc
index c5329640dc..6d559c4e51 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.cc
+++ b/test/core/end2end/fixtures/h2_full+pipe.cc
@@ -105,7 +105,7 @@ int main(int argc, char** argv) {
grpc_allow_specialized_wakeup_fd = 0;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_full+trace.cc b/test/core/end2end/fixtures/h2_full+trace.cc
index ba7a780304..2bbad48701 100644
--- a/test/core/end2end/fixtures/h2_full+trace.cc
+++ b/test/core/end2end/fixtures/h2_full+trace.cc
@@ -113,7 +113,7 @@ int main(int argc, char** argv) {
g_fixture_slowdown_factor = 10;
#endif
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_full+workarounds.cc b/test/core/end2end/fixtures/h2_full+workarounds.cc
index 78da8418f6..cb0f7d275b 100644
--- a/test/core/end2end/fixtures/h2_full+workarounds.cc
+++ b/test/core/end2end/fixtures/h2_full+workarounds.cc
@@ -114,7 +114,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_full.cc b/test/core/end2end/fixtures/h2_full.cc
index 0c826b6836..c0d21288c7 100644
--- a/test/core/end2end/fixtures/h2_full.cc
+++ b/test/core/end2end/fixtures/h2_full.cc
@@ -97,7 +97,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_http_proxy.cc b/test/core/end2end/fixtures/h2_http_proxy.cc
index 0af8a29a15..9b6a81494e 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.cc
+++ b/test/core/end2end/fixtures/h2_http_proxy.cc
@@ -120,7 +120,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_local.cc b/test/core/end2end/fixtures/h2_local.cc
index cce8f1745a..18d690ff22 100644
--- a/test/core/end2end/fixtures/h2_local.cc
+++ b/test/core/end2end/fixtures/h2_local.cc
@@ -140,7 +140,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_oauth2.cc b/test/core/end2end/fixtures/h2_oauth2.cc
index 37397d6450..113a6b1173 100644
--- a/test/core/end2end/fixtures/h2_oauth2.cc
+++ b/test/core/end2end/fixtures/h2_oauth2.cc
@@ -224,7 +224,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_proxy.cc b/test/core/end2end/fixtures/h2_proxy.cc
index a32000061a..e334396ea7 100644
--- a/test/core/end2end/fixtures/h2_proxy.cc
+++ b/test/core/end2end/fixtures/h2_proxy.cc
@@ -124,7 +124,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc
index eb71e24c77..45f78b5964 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.cc
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc
@@ -53,7 +53,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server), 0);
+ grpc_server_get_channel_args(f->server), nullptr);
}
typedef struct {
@@ -140,7 +140,7 @@ int main(int argc, char** argv) {
g_fixture_slowdown_factor = 10;
#endif
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_sockpair.cc b/test/core/end2end/fixtures/h2_sockpair.cc
index 904bda5458..77bce7ebb3 100644
--- a/test/core/end2end/fixtures/h2_sockpair.cc
+++ b/test/core/end2end/fixtures/h2_sockpair.cc
@@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server), 0);
+ grpc_server_get_channel_args(f->server), nullptr);
}
typedef struct {
@@ -126,7 +126,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.cc b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
index 45f7f254ac..ac37841dc4 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.cc
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
@@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server), 0);
+ grpc_server_get_channel_args(f->server), nullptr);
}
typedef struct {
@@ -140,7 +140,7 @@ int main(int argc, char** argv) {
g_fixture_slowdown_factor = 2;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/h2_ssl.cc b/test/core/end2end/fixtures/h2_ssl.cc
index 4d6c815716..1fcd785e25 100644
--- a/test/core/end2end/fixtures/h2_ssl.cc
+++ b/test/core/end2end/fixtures/h2_ssl.cc
@@ -158,7 +158,7 @@ int main(int argc, char** argv) {
size_t roots_size = strlen(test_root_cert);
char* roots_filename;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
/* Set the SSL roots env var. */
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.cc b/test/core/end2end/fixtures/h2_ssl_proxy.cc
index 09cbf974b6..f185807942 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.cc
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.cc
@@ -199,7 +199,7 @@ int main(int argc, char** argv) {
size_t roots_size = strlen(test_root_cert);
char* roots_filename;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
/* Set the SSL roots env var. */
diff --git a/test/core/end2end/fixtures/h2_uds.cc b/test/core/end2end/fixtures/h2_uds.cc
index 2c81c3d362..f251bbd28c 100644
--- a/test/core/end2end/fixtures/h2_uds.cc
+++ b/test/core/end2end/fixtures/h2_uds.cc
@@ -102,7 +102,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fixtures/inproc.cc b/test/core/end2end/fixtures/inproc.cc
index be6eda8483..dadf3ef455 100644
--- a/test/core/end2end/fixtures/inproc.cc
+++ b/test/core/end2end/fixtures/inproc.cc
@@ -83,7 +83,7 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char** argv) {
size_t i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_end2end_tests_pre_init();
grpc_init();
diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc
index e97a544e12..a3de56d4f9 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.cc
+++ b/test/core/end2end/fuzzers/api_fuzzer.cc
@@ -378,7 +378,7 @@ grpc_ares_request* my_dns_lookup_ares_locked(
const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout, grpc_combiner* combiner) {
addr_req* r = static_cast<addr_req*>(gpr_malloc(sizeof(*r)));
r->addr = gpr_strdup(addr);
r->on_done = on_done;
@@ -420,7 +420,7 @@ static void do_connect(void* arg, grpc_error* error) {
grpc_transport* transport =
grpc_create_chttp2_transport(nullptr, server, false);
- grpc_server_setup_transport(g_server, transport, nullptr, nullptr, 0);
+ grpc_server_setup_transport(g_server, transport, nullptr, nullptr, nullptr);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
GRPC_CLOSURE_SCHED(fc->closure, GRPC_ERROR_NONE);
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index a79fe5ad95..0469421c97 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -35,6 +35,7 @@
"\x1Fgrpc.max_response_message_bytes"
"$/grpc.lb.v1.LoadBalancer/BalanceLoad"
"\x1C/grpc.health.v1.Health/Watch"
+"P/envoy.service.discovery.v2.AggregatedDiscoveryService/StreamAggregatedResources"
"\x07deflate"
"\x04gzip"
"\x0Bstream/gzip"
diff --git a/test/core/end2end/fuzzers/server_fuzzer.cc b/test/core/end2end/fuzzers/server_fuzzer.cc
index bd686215dd..d370dc7de8 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.cc
+++ b/test/core/end2end/fuzzers/server_fuzzer.cc
@@ -62,7 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
grpc_server_start(server);
grpc_transport* transport =
grpc_create_chttp2_transport(nullptr, mock_endpoint, false);
- grpc_server_setup_transport(server, transport, nullptr, nullptr, 0);
+ grpc_server_setup_transport(server, transport, nullptr, nullptr, nullptr);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
grpc_call* call1 = nullptr;
diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc
index 3f1c5596ad..66e8ca5161 100644
--- a/test/core/end2end/goaway_server_test.cc
+++ b/test/core/end2end/goaway_server_test.cc
@@ -48,7 +48,7 @@ static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)(
const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addresses, bool check_grpclb,
- char** service_config_json, grpc_combiner* combiner);
+ char** service_config_json, int query_timeout_ms, grpc_combiner* combiner);
static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request);
@@ -104,11 +104,11 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+ int query_timeout_ms, grpc_combiner* combiner) {
if (0 != strcmp(addr, "test")) {
return iomgr_dns_lookup_ares_locked(
dns_server, addr, default_port, interested_parties, on_done, lb_addrs,
- check_grpclb, service_config_json, combiner);
+ check_grpclb, service_config_json, query_timeout_ms, combiner);
}
grpc_error* error = GRPC_ERROR_NONE;
@@ -144,7 +144,7 @@ int main(int argc, char** argv) {
grpc_op ops[6];
grpc_op* op;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
gpr_mu_init(&g_mu);
grpc_init();
diff --git a/test/core/end2end/h2_ssl_cert_test.cc b/test/core/end2end/h2_ssl_cert_test.cc
index 2c5ee3b156..cb0800bf89 100644
--- a/test/core/end2end/h2_ssl_cert_test.cc
+++ b/test/core/end2end/h2_ssl_cert_test.cc
@@ -358,7 +358,7 @@ int main(int argc, char** argv) {
size_t roots_size = strlen(test_root_cert);
char* roots_filename;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* Set the SSL roots env var. */
roots_file =
gpr_tmpfile("chttp2_simple_ssl_cert_fullstack_test", &roots_filename);
diff --git a/test/core/end2end/h2_ssl_session_reuse_test.cc b/test/core/end2end/h2_ssl_session_reuse_test.cc
index b2f398625a..fbcdcc4b3f 100644
--- a/test/core/end2end/h2_ssl_session_reuse_test.cc
+++ b/test/core/end2end/h2_ssl_session_reuse_test.cc
@@ -258,7 +258,7 @@ int main(int argc, char** argv) {
size_t roots_size = strlen(test_root_cert);
char* roots_filename;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* Set the SSL roots env var. */
roots_file = gpr_tmpfile("chttp2_ssl_session_reuse_test", &roots_filename);
GPR_ASSERT(roots_filename != nullptr);
diff --git a/test/core/end2end/inproc_callback_test.cc b/test/core/end2end/inproc_callback_test.cc
index 310030046a..72ad992d54 100644
--- a/test/core/end2end/inproc_callback_test.cc
+++ b/test/core/end2end/inproc_callback_test.cc
@@ -495,7 +495,7 @@ static grpc_end2end_test_config configs[] = {
};
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
simple_request_pre_init();
diff --git a/test/core/end2end/invalid_call_argument_test.cc b/test/core/end2end/invalid_call_argument_test.cc
index 6cb2e3ee80..bd28d19298 100644
--- a/test/core/end2end/invalid_call_argument_test.cc
+++ b/test/core/end2end/invalid_call_argument_test.cc
@@ -609,7 +609,7 @@ static void test_invalid_initial_metadata_reserved_key() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_invalid_initial_metadata_reserved_key();
test_non_null_reserved_on_start_batch();
diff --git a/test/core/end2end/multiple_server_queues_test.cc b/test/core/end2end/multiple_server_queues_test.cc
index dfa3b48b52..5ae828c1e3 100644
--- a/test/core/end2end/multiple_server_queues_test.cc
+++ b/test/core/end2end/multiple_server_queues_test.cc
@@ -27,7 +27,7 @@ int main(int argc, char** argv) {
grpc_server* server;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
attr.version = 1;
diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc
index e8ce4032e0..5dda748f5a 100644
--- a/test/core/end2end/no_server_test.cc
+++ b/test/core/end2end/no_server_test.cc
@@ -107,7 +107,7 @@ void run_test(bool wait_for_ready) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
run_test(true /* wait_for_ready */);
run_test(false /* wait_for_ready */);
return 0;
diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc
index 7c61b7910b..49a0bc8011 100644
--- a/test/core/end2end/tests/channelz.cc
+++ b/test/core/end2end/tests/channelz.cc
@@ -29,6 +29,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
+#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/string.h"
#include "test/core/end2end/cq_verifier.h"
@@ -238,7 +239,6 @@ static void test_channelz(grpc_end2end_test_config config) {
json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
- gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\""));
GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\""));
GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
@@ -250,7 +250,6 @@ static void test_channelz(grpc_end2end_test_config config) {
json = channelz_server->RenderJsonString();
GPR_ASSERT(json != nullptr);
- gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\""));
GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\""));
GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
@@ -261,7 +260,7 @@ static void test_channelz(grpc_end2end_test_config config) {
gpr_free(json);
json = channelz_server->RenderServerSockets(0);
- GPR_ASSERT(nullptr != strstr(json, "\"socketRef\":"));
+ GPR_ASSERT(nullptr != strstr(json, "\"end\":true"));
gpr_free(json);
end_test(&f);
@@ -292,7 +291,6 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) {
char* json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
- gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"trace\""));
GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\""));
GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\""));
@@ -300,7 +298,6 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) {
json = channelz_server->RenderJsonString();
GPR_ASSERT(json != nullptr);
- gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"trace\""));
GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Server created\""));
GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\""));
diff --git a/test/core/end2end/tests/streaming_error_response.cc b/test/core/end2end/tests/streaming_error_response.cc
index 4c357e077e..713975a33f 100644
--- a/test/core/end2end/tests/streaming_error_response.cc
+++ b/test/core/end2end/tests/streaming_error_response.cc
@@ -89,7 +89,8 @@ static void end_test(grpc_end2end_test_fixture* f) {
}
/* Client sends a request with payload, server reads then returns status. */
-static void test(grpc_end2end_test_config config, bool request_status_early) {
+static void test(grpc_end2end_test_config config, bool request_status_early,
+ bool recv_message_separately) {
grpc_call* c;
grpc_call* s;
grpc_slice response_payload1_slice = grpc_slice_from_copied_string("hello");
@@ -116,6 +117,7 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
int was_cancelled = 2;
gpr_timespec deadline = five_seconds_from_now();
+ GPR_ASSERT(!recv_message_separately || request_status_early);
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"), nullptr,
deadline, nullptr);
@@ -136,9 +138,11 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
- op->op = GRPC_OP_RECV_MESSAGE;
- op->data.recv_message.recv_message = &response_payload1_recv;
- op++;
+ if (!recv_message_separately) {
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message.recv_message = &response_payload1_recv;
+ op++;
+ }
if (request_status_early) {
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
@@ -168,10 +172,24 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
+ if (recv_message_separately) {
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message.recv_message = &response_payload1_recv;
+ op++;
+ error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+ nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ }
+
CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
if (!request_status_early) {
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
}
+ if (recv_message_separately) {
+ CQ_EXPECT_COMPLETION(cqv, tag(4), 1);
+ }
cq_verify(cqv);
memset(ops, 0, sizeof(ops));
@@ -265,8 +283,9 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
}
void streaming_error_response(grpc_end2end_test_config config) {
- test(config, false);
- test(config, true);
+ test(config, false, false);
+ test(config, true, false);
+ test(config, true, true);
}
void streaming_error_response_pre_init(void) {}
diff --git a/test/core/fling/client.cc b/test/core/fling/client.cc
index 05dc3052d1..2a7a5ca623 100644
--- a/test/core/fling/client.cc
+++ b/test/core/fling/client.cc
@@ -158,11 +158,11 @@ int main(int argc, char** argv) {
gpr_timers_set_log_filename("latency_trace.fling_client.txt");
- grpc_init();
-
GPR_ASSERT(argc >= 1);
fake_argv[0] = argv[0];
- grpc_test_init(1, fake_argv);
+ grpc::testing::TestEnvironment env(1, fake_argv);
+
+ grpc_init();
int warmup_seconds = 1;
int benchmark_seconds = 5;
diff --git a/test/core/gpr/BUILD b/test/core/gpr/BUILD
index d58d4f2a14..67657ee1ce 100644
--- a/test/core/gpr/BUILD
+++ b/test/core/gpr/BUILD
@@ -81,12 +81,12 @@ grpc_cc_test(
grpc_cc_test(
name = "mpscq_test",
srcs = ["mpscq_test.cc"],
+ exec_compatible_with = ["//third_party/toolchains/machine_size:large"],
language = "C++",
deps = [
"//:gpr",
"//test/core/util:gpr_test_util",
],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
)
grpc_cc_test(
diff --git a/test/core/gpr/alloc_test.cc b/test/core/gpr/alloc_test.cc
index 36cdc02ff2..0b110e2b77 100644
--- a/test/core/gpr/alloc_test.cc
+++ b/test/core/gpr/alloc_test.cc
@@ -64,7 +64,7 @@ static void test_malloc_aligned() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_custom_allocs();
test_malloc_aligned();
return 0;
diff --git a/test/core/gpr/arena_test.cc b/test/core/gpr/arena_test.cc
index 3e7c906591..de4bd9804e 100644
--- a/test/core/gpr/arena_test.cc
+++ b/test/core/gpr/arena_test.cc
@@ -116,7 +116,7 @@ static void concurrent_test(void) {
}
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_noop();
TEST(0_1, 0, 1);
diff --git a/test/core/gpr/cpu_test.cc b/test/core/gpr/cpu_test.cc
index 1052d40b42..dbaeb08c18 100644
--- a/test/core/gpr/cpu_test.cc
+++ b/test/core/gpr/cpu_test.cc
@@ -144,7 +144,7 @@ static void cpu_test(void) {
}
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
cpu_test();
return 0;
}
diff --git a/test/core/gpr/env_test.cc b/test/core/gpr/env_test.cc
index 3f4b493239..a8206bd3cf 100644
--- a/test/core/gpr/env_test.cc
+++ b/test/core/gpr/env_test.cc
@@ -43,7 +43,7 @@ static void test_setenv_getenv(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_setenv_getenv();
return 0;
}
diff --git a/test/core/gpr/host_port_test.cc b/test/core/gpr/host_port_test.cc
index b5d88b2b01..b01bbf4b69 100644
--- a/test/core/gpr/host_port_test.cc
+++ b/test/core/gpr/host_port_test.cc
@@ -50,7 +50,7 @@ static void test_join_host_port_garbage(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_join_host_port();
test_join_host_port_garbage();
diff --git a/test/core/gpr/log_test.cc b/test/core/gpr/log_test.cc
index 839ff0aef9..f96257738b 100644
--- a/test/core/gpr/log_test.cc
+++ b/test/core/gpr/log_test.cc
@@ -53,7 +53,7 @@ static void test_should_not_log(gpr_log_func_args* args) { GPR_ASSERT(false); }
gpr_log(SEVERITY, "hello %d %d %d", 1, 2, 3);
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* test logging at various verbosity levels */
gpr_log(GPR_DEBUG, "%s", "hello world");
gpr_log(GPR_INFO, "%s", "hello world");
diff --git a/test/core/gpr/mpscq_test.cc b/test/core/gpr/mpscq_test.cc
index f51bdf8c50..c826ccb498 100644
--- a/test/core/gpr/mpscq_test.cc
+++ b/test/core/gpr/mpscq_test.cc
@@ -182,7 +182,7 @@ static void test_mt_multipop(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_serial();
test_mt();
test_mt_multipop();
diff --git a/test/core/gpr/murmur_hash_test.cc b/test/core/gpr/murmur_hash_test.cc
index 2d2fa72cfb..fdc2cfa76b 100644
--- a/test/core/gpr/murmur_hash_test.cc
+++ b/test/core/gpr/murmur_hash_test.cc
@@ -64,7 +64,7 @@ static void verification_test(hash_func hash, uint32_t expected) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* basic tests to verify that things don't crash */
gpr_murmur_hash3("", 0, 0);
gpr_murmur_hash3("xyz", 3, 0);
diff --git a/test/core/gpr/spinlock_test.cc b/test/core/gpr/spinlock_test.cc
index 0ee72edb15..8bd9396da6 100644
--- a/test/core/gpr/spinlock_test.cc
+++ b/test/core/gpr/spinlock_test.cc
@@ -149,7 +149,7 @@ static void inctry(void* v /*=m*/) {
/* ------------------------------------------------- */
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test("spinlock", &inc, 1, 1);
test("spinlock try", &inctry, 1, 1);
return 0;
diff --git a/test/core/gpr/string_test.cc b/test/core/gpr/string_test.cc
index 9f3b312465..7da7b18778 100644
--- a/test/core/gpr/string_test.cc
+++ b/test/core/gpr/string_test.cc
@@ -295,7 +295,7 @@ static void test_is_true(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_strdup();
test_dump();
test_parse_uint32();
diff --git a/test/core/gpr/sync_test.cc b/test/core/gpr/sync_test.cc
index 24b4562819..fc7216e360 100644
--- a/test/core/gpr/sync_test.cc
+++ b/test/core/gpr/sync_test.cc
@@ -458,7 +458,7 @@ static void refcheck(void* v /*=m*/) {
/* ------------------------------------------------- */
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test("mutex", &inc, nullptr, 1, 1);
test("mutex try", &inctry, nullptr, 1, 1);
test("cv", &inc_by_turns, nullptr, 1, 1);
diff --git a/test/core/gpr/time_test.cc b/test/core/gpr/time_test.cc
index 6f070f58df..a32cbfb09a 100644
--- a/test/core/gpr/time_test.cc
+++ b/test/core/gpr/time_test.cc
@@ -254,7 +254,7 @@ static void test_cmp_extreme(void) {
}
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_values();
test_add_sub();
diff --git a/test/core/gpr/tls_test.cc b/test/core/gpr/tls_test.cc
index 0502fc7ef4..d1bed0aafe 100644
--- a/test/core/gpr/tls_test.cc
+++ b/test/core/gpr/tls_test.cc
@@ -50,7 +50,7 @@ static void thd_body(void* arg) {
int main(int argc, char* argv[]) {
grpc_core::Thread threads[NUM_THREADS];
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
gpr_tls_init(&test_var);
diff --git a/test/core/gpr/useful_test.cc b/test/core/gpr/useful_test.cc
index 619c800c4d..4f8582ab41 100644
--- a/test/core/gpr/useful_test.cc
+++ b/test/core/gpr/useful_test.cc
@@ -26,7 +26,7 @@ int main(int argc, char** argv) {
int four[4];
int five[5];
uint32_t bitset = 0;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
GPR_ASSERT(GPR_MIN(1, 2) == 1);
GPR_ASSERT(GPR_MAX(1, 2) == 2);
diff --git a/test/core/gprpp/fork_test.cc b/test/core/gprpp/fork_test.cc
index 642f910489..0f56eead49 100644
--- a/test/core/gprpp/fork_test.cc
+++ b/test/core/gprpp/fork_test.cc
@@ -130,7 +130,7 @@ static void test_exec_count() {
}
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_init();
test_thd_count();
test_exec_count();
diff --git a/test/core/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc
index 73e0773b31..f943128f53 100644
--- a/test/core/gprpp/inlined_vector_test.cc
+++ b/test/core/gprpp/inlined_vector_test.cc
@@ -116,7 +116,7 @@ typedef InlinedVector<int, kInlinedLength> IntVec8;
const size_t kInlinedFillSize = kInlinedLength - 1;
const size_t kAllocatedFillSize = kInlinedLength + 1;
-TEST(InlinedVectorTest, CopyConstructerInlined) {
+TEST(InlinedVectorTest, CopyConstructorInlined) {
IntVec8 original;
FillVector(&original, kInlinedFillSize);
IntVec8 copy_constructed(original);
@@ -125,7 +125,7 @@ TEST(InlinedVectorTest, CopyConstructerInlined) {
}
}
-TEST(InlinedVectorTest, CopyConstructerAllocated) {
+TEST(InlinedVectorTest, CopyConstructorAllocated) {
IntVec8 original;
FillVector(&original, kAllocatedFillSize);
IntVec8 copy_constructed(original);
@@ -264,6 +264,166 @@ TEST(InlinedVectorTest, MoveAssignmentAllocatedAllocated) {
EXPECT_EQ(move_assigned.data(), old_data);
}
+// A copyable and movable value class, used to test that elements' copy
+// and move methods are called correctly.
+class Value {
+ public:
+ explicit Value(int v) : value_(MakeUnique<int>(v)) {}
+
+ // copyable
+ Value(const Value& v) {
+ value_ = MakeUnique<int>(*v.value_);
+ copied_ = true;
+ }
+ Value& operator=(const Value& v) {
+ value_ = MakeUnique<int>(*v.value_);
+ copied_ = true;
+ return *this;
+ }
+
+ // movable
+ Value(Value&& v) {
+ value_ = std::move(v.value_);
+ moved_ = true;
+ }
+ Value& operator=(Value&& v) {
+ value_ = std::move(v.value_);
+ moved_ = true;
+ return *this;
+ }
+
+ const UniquePtr<int>& value() const { return value_; }
+ bool copied() const { return copied_; }
+ bool moved() const { return moved_; }
+
+ private:
+ UniquePtr<int> value_;
+ bool copied_ = false;
+ bool moved_ = false;
+};
+
+TEST(InlinedVectorTest, CopyConstructorCopiesElementsInlined) {
+ InlinedVector<Value, 1> v1;
+ v1.emplace_back(3);
+ InlinedVector<Value, 1> v2(v1);
+ EXPECT_EQ(v2.size(), 1UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ // Addresses should differ.
+ EXPECT_NE(v1[0].value().get(), v2[0].value().get());
+ EXPECT_TRUE(v2[0].copied());
+}
+
+TEST(InlinedVectorTest, CopyConstructorCopiesElementsAllocated) {
+ InlinedVector<Value, 1> v1;
+ v1.reserve(2);
+ v1.emplace_back(3);
+ v1.emplace_back(5);
+ InlinedVector<Value, 1> v2(v1);
+ EXPECT_EQ(v2.size(), 2UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(*v2[1].value(), 5);
+ // Addresses should differ.
+ EXPECT_NE(v1[0].value().get(), v2[0].value().get());
+ EXPECT_NE(v1[1].value().get(), v2[1].value().get());
+ EXPECT_TRUE(v2[0].copied());
+ EXPECT_TRUE(v2[1].copied());
+}
+
+TEST(InlinedVectorTest, CopyAssignmentCopiesElementsInlined) {
+ InlinedVector<Value, 1> v1;
+ v1.emplace_back(3);
+ InlinedVector<Value, 1> v2;
+ EXPECT_EQ(v2.size(), 0UL);
+ v2 = v1;
+ EXPECT_EQ(v2.size(), 1UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ // Addresses should differ.
+ EXPECT_NE(v1[0].value().get(), v2[0].value().get());
+ EXPECT_TRUE(v2[0].copied());
+}
+
+TEST(InlinedVectorTest, CopyAssignmentCopiesElementsAllocated) {
+ InlinedVector<Value, 1> v1;
+ v1.reserve(2);
+ v1.emplace_back(3);
+ v1.emplace_back(5);
+ InlinedVector<Value, 1> v2;
+ EXPECT_EQ(v2.size(), 0UL);
+ v2 = v1;
+ EXPECT_EQ(v2.size(), 2UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(*v2[1].value(), 5);
+ // Addresses should differ.
+ EXPECT_NE(v1[0].value().get(), v2[0].value().get());
+ EXPECT_NE(v1[1].value().get(), v2[1].value().get());
+ EXPECT_TRUE(v2[0].copied());
+ EXPECT_TRUE(v2[1].copied());
+}
+
+TEST(InlinedVectorTest, MoveConstructorMovesElementsInlined) {
+ InlinedVector<Value, 1> v1;
+ v1.emplace_back(3);
+ int* addr = v1[0].value().get();
+ InlinedVector<Value, 1> v2(std::move(v1));
+ EXPECT_EQ(v2.size(), 1UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(addr, v2[0].value().get());
+ EXPECT_TRUE(v2[0].moved());
+}
+
+TEST(InlinedVectorTest, MoveConstructorMovesElementsAllocated) {
+ InlinedVector<Value, 1> v1;
+ v1.reserve(2);
+ v1.emplace_back(3);
+ v1.emplace_back(5);
+ int* addr1 = v1[0].value().get();
+ int* addr2 = v1[1].value().get();
+ Value* data1 = v1.data();
+ InlinedVector<Value, 1> v2(std::move(v1));
+ EXPECT_EQ(v2.size(), 2UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(*v2[1].value(), 5);
+ EXPECT_EQ(addr1, v2[0].value().get());
+ EXPECT_EQ(addr2, v2[1].value().get());
+ // In this case, elements won't be moved, because we have just stolen
+ // the underlying storage.
+ EXPECT_EQ(data1, v2.data());
+}
+
+TEST(InlinedVectorTest, MoveAssignmentMovesElementsInlined) {
+ InlinedVector<Value, 1> v1;
+ v1.emplace_back(3);
+ int* addr = v1[0].value().get();
+ InlinedVector<Value, 1> v2;
+ EXPECT_EQ(v2.size(), 0UL);
+ v2 = std::move(v1);
+ EXPECT_EQ(v2.size(), 1UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(addr, v2[0].value().get());
+ EXPECT_TRUE(v2[0].moved());
+}
+
+TEST(InlinedVectorTest, MoveAssignmentMovesElementsAllocated) {
+ InlinedVector<Value, 1> v1;
+ v1.reserve(2);
+ v1.emplace_back(3);
+ v1.emplace_back(5);
+ int* addr1 = v1[0].value().get();
+ int* addr2 = v1[1].value().get();
+ Value* data1 = v1.data();
+ InlinedVector<Value, 1> v2;
+ EXPECT_EQ(v2.size(), 0UL);
+ v2 = std::move(v1);
+ EXPECT_EQ(v2.size(), 2UL);
+ EXPECT_EQ(*v2[0].value(), 3);
+ EXPECT_EQ(*v2[1].value(), 5);
+ EXPECT_EQ(addr1, v2[0].value().get());
+ EXPECT_EQ(addr2, v2[1].value().get());
+ // In this case, elements won't be moved, because we have just stolen
+ // the underlying storage.
+ EXPECT_EQ(data1, v2.data());
+}
+
TEST(InlinedVectorTest, PopBackInlined) {
InlinedVector<UniquePtr<int>, 2> v;
// Add two elements, pop one out
@@ -294,7 +454,7 @@ TEST(InlinedVectorTest, PopBackAllocated) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/gprpp/manual_constructor_test.cc b/test/core/gprpp/manual_constructor_test.cc
index af162ae8e8..a5a45133d8 100644
--- a/test/core/gprpp/manual_constructor_test.cc
+++ b/test/core/gprpp/manual_constructor_test.cc
@@ -92,7 +92,7 @@ static void complex_test() {
/* ------------------------------------------------- */
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
basic_test();
complex_test();
return 0;
diff --git a/test/core/gprpp/memory_test.cc b/test/core/gprpp/memory_test.cc
index 180c36fad7..bb6a219a84 100644
--- a/test/core/gprpp/memory_test.cc
+++ b/test/core/gprpp/memory_test.cc
@@ -68,7 +68,7 @@ TEST(MemoryTest, UniquePtrWithCustomDeleter) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/gprpp/orphanable_test.cc b/test/core/gprpp/orphanable_test.cc
index ad6b9ac867..fe13df0d0d 100644
--- a/test/core/gprpp/orphanable_test.cc
+++ b/test/core/gprpp/orphanable_test.cc
@@ -83,11 +83,11 @@ TEST(OrphanablePtr, InternallyRefCounted) {
// things build properly in both debug and non-debug cases.
DebugOnlyTraceFlag baz_tracer(true, "baz");
-class Baz : public InternallyRefCountedWithTracing<Baz> {
+class Baz : public InternallyRefCounted<Baz> {
public:
Baz() : Baz(0) {}
explicit Baz(int value)
- : InternallyRefCountedWithTracing<Baz>(&baz_tracer), value_(value) {}
+ : InternallyRefCounted<Baz>(&baz_tracer), value_(value) {}
void Orphan() override { Unref(); }
int value() const { return value_; }
@@ -114,7 +114,7 @@ TEST(OrphanablePtr, InternallyRefCountedWithTracing) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/gprpp/ref_counted_ptr_test.cc b/test/core/gprpp/ref_counted_ptr_test.cc
index 463b5e8966..96dbdf884b 100644
--- a/test/core/gprpp/ref_counted_ptr_test.cc
+++ b/test/core/gprpp/ref_counted_ptr_test.cc
@@ -163,9 +163,9 @@ TEST(MakeRefCounted, Args) {
TraceFlag foo_tracer(true, "foo");
-class FooWithTracing : public RefCountedWithTracing<FooWithTracing> {
+class FooWithTracing : public RefCounted<FooWithTracing> {
public:
- FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
+ FooWithTracing() : RefCounted(&foo_tracer) {}
};
TEST(RefCountedPtr, RefCountedWithTracing) {
@@ -241,7 +241,7 @@ TEST(RefCountedPtr, CanPassSubclassToFunctionExpectingSubclass) {
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/gprpp/ref_counted_test.cc b/test/core/gprpp/ref_counted_test.cc
index f85a2e4675..1955be3311 100644
--- a/test/core/gprpp/ref_counted_test.cc
+++ b/test/core/gprpp/ref_counted_test.cc
@@ -29,7 +29,10 @@ namespace {
class Foo : public RefCounted<Foo> {
public:
- Foo() {}
+ Foo() {
+ static_assert(std::has_virtual_destructor<Foo>::value,
+ "PolymorphicRefCount doesn't have a virtual dtor");
+ }
};
TEST(RefCounted, Basic) {
@@ -45,13 +48,35 @@ TEST(RefCounted, ExtraRef) {
foo->Unref();
}
+class FooNonPolymorphic
+ : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
+ public:
+ FooNonPolymorphic() {
+ static_assert(!std::has_virtual_destructor<FooNonPolymorphic>::value,
+ "NonPolymorphicRefCount has a virtual dtor");
+ }
+};
+
+TEST(RefCountedNonPolymorphic, Basic) {
+ FooNonPolymorphic* foo = New<FooNonPolymorphic>();
+ foo->Unref();
+}
+
+TEST(RefCountedNonPolymorphic, ExtraRef) {
+ FooNonPolymorphic* foo = New<FooNonPolymorphic>();
+ RefCountedPtr<FooNonPolymorphic> foop = foo->Ref();
+ foop.release();
+ foo->Unref();
+ foo->Unref();
+}
+
// Note: We use DebugOnlyTraceFlag instead of TraceFlag to ensure that
// things build properly in both debug and non-debug cases.
DebugOnlyTraceFlag foo_tracer(true, "foo");
-class FooWithTracing : public RefCountedWithTracing<FooWithTracing> {
+class FooWithTracing : public RefCounted<FooWithTracing> {
public:
- FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
+ FooWithTracing() : RefCounted(&foo_tracer) {}
};
TEST(RefCountedWithTracing, Basic) {
@@ -66,12 +91,31 @@ TEST(RefCountedWithTracing, Basic) {
foo->Unref(DEBUG_LOCATION, "original_ref");
}
+class FooNonPolymorphicWithTracing
+ : public RefCounted<FooNonPolymorphicWithTracing, NonPolymorphicRefCount> {
+ public:
+ FooNonPolymorphicWithTracing() : RefCounted(&foo_tracer) {}
+};
+
+TEST(RefCountedNonPolymorphicWithTracing, Basic) {
+ FooNonPolymorphicWithTracing* foo = New<FooNonPolymorphicWithTracing>();
+ RefCountedPtr<FooNonPolymorphicWithTracing> foop =
+ foo->Ref(DEBUG_LOCATION, "extra_ref");
+ foop.release();
+ foo->Unref(DEBUG_LOCATION, "extra_ref");
+ // Can use the no-argument methods, too.
+ foop = foo->Ref();
+ foop.release();
+ foo->Unref();
+ foo->Unref(DEBUG_LOCATION, "original_ref");
+}
+
} // namespace
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/gprpp/thd_test.cc b/test/core/gprpp/thd_test.cc
index 82dd681049..06aa58984b 100644
--- a/test/core/gprpp/thd_test.cc
+++ b/test/core/gprpp/thd_test.cc
@@ -92,7 +92,7 @@ static void test2(void) {
/* ------------------------------------------------- */
int main(int argc, char* argv[]) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test1();
test2();
return 0;
diff --git a/test/core/http/format_request_test.cc b/test/core/http/format_request_test.cc
index 353e138b2a..b0a90c4613 100644
--- a/test/core/http/format_request_test.cc
+++ b/test/core/http/format_request_test.cc
@@ -138,7 +138,7 @@ static void test_format_post_request_content_type_override(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_format_get_request();
diff --git a/test/core/http/httpcli_test.cc b/test/core/http/httpcli_test.cc
index a51a0a5f6d..bfd75f8649 100644
--- a/test/core/http/httpcli_test.cc
+++ b/test/core/http/httpcli_test.cc
@@ -145,7 +145,7 @@ static void destroy_pops(void* p, grpc_error* error) {
int main(int argc, char** argv) {
gpr_subprocess* server;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_closure destroyed;
diff --git a/test/core/http/httpscli_test.cc b/test/core/http/httpscli_test.cc
index 3fecf2b08b..326b0e95e2 100644
--- a/test/core/http/httpscli_test.cc
+++ b/test/core/http/httpscli_test.cc
@@ -201,7 +201,7 @@ int main(int argc, char** argv) {
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(5, GPR_TIMESPAN)));
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
grpc_httpcli_context_init(&g_context);
grpc_pollset* pollset =
diff --git a/test/core/http/parser_test.cc b/test/core/http/parser_test.cc
index fe824f57fc..d105b40bcd 100644
--- a/test/core/http/parser_test.cc
+++ b/test/core/http/parser_test.cc
@@ -218,7 +218,7 @@ int main(int argc, char** argv) {
GRPC_SLICE_SPLIT_ONE_BYTE};
char *tmp1, *tmp2;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
for (i = 0; i < GPR_ARRAY_SIZE(split_modes); i++) {
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 70ee83acd2..e278632e50 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -40,7 +40,7 @@ grpc_cc_library(
grpc_cc_test(
name = "combiner_test",
srcs = ["combiner_test.cc"],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
+ exec_compatible_with = ["//third_party/toolchains/machine_size:large"],
language = "C++",
deps = [
"//:gpr",
diff --git a/test/core/iomgr/buffer_list_test.cc b/test/core/iomgr/buffer_list_test.cc
index c7f30fa092..eca8f76e67 100644
--- a/test/core/iomgr/buffer_list_test.cc
+++ b/test/core/iomgr/buffer_list_test.cc
@@ -50,7 +50,7 @@ static void TestShutdownFlushesList() {
grpc_core::TracedBuffer::AddNewEntry(
&list, i, static_cast<void*>(&verifier_called[i]));
}
- grpc_core::TracedBuffer::Shutdown(&list, GRPC_ERROR_NONE);
+ grpc_core::TracedBuffer::Shutdown(&list, nullptr, GRPC_ERROR_NONE);
GPR_ASSERT(list == nullptr);
for (auto i = 0; i < NUM_ELEM; i++) {
GPR_ASSERT(gpr_atm_acq_load(&verifier_called[i]) ==
@@ -88,7 +88,7 @@ static void TestVerifierCalledOnAck() {
grpc_core::TracedBuffer::ProcessTimestamp(&list, &serr, &tss);
GPR_ASSERT(gpr_atm_acq_load(&verifier_called) == static_cast<gpr_atm>(1));
GPR_ASSERT(list == nullptr);
- grpc_core::TracedBuffer::Shutdown(&list, GRPC_ERROR_NONE);
+ grpc_core::TracedBuffer::Shutdown(&list, nullptr, GRPC_ERROR_NONE);
}
static void TestTcpBufferList() {
@@ -97,7 +97,7 @@ static void TestTcpBufferList() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
TestTcpBufferList();
grpc_shutdown();
diff --git a/test/core/iomgr/combiner_test.cc b/test/core/iomgr/combiner_test.cc
index cf2c7db846..c39c3fc8fc 100644
--- a/test/core/iomgr/combiner_test.cc
+++ b/test/core/iomgr/combiner_test.cc
@@ -144,7 +144,7 @@ static void test_execute_finally(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_no_op();
test_execute_one();
diff --git a/test/core/iomgr/endpoint_pair_test.cc b/test/core/iomgr/endpoint_pair_test.cc
index ad38076b51..3ddbe7f2fc 100644
--- a/test/core/iomgr/endpoint_pair_test.cc
+++ b/test/core/iomgr/endpoint_pair_test.cc
@@ -60,7 +60,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/error_test.cc b/test/core/iomgr/error_test.cc
index d78a8c2af3..3ba90147aa 100644
--- a/test/core/iomgr/error_test.cc
+++ b/test/core/iomgr/error_test.cc
@@ -215,7 +215,7 @@ static void test_overflow() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_set_get_int();
test_set_get_str();
diff --git a/test/core/iomgr/ev_epollex_linux_test.cc b/test/core/iomgr/ev_epollex_linux_test.cc
index 08d1e68b39..faa3ef344a 100644
--- a/test/core/iomgr/ev_epollex_linux_test.cc
+++ b/test/core/iomgr/ev_epollex_linux_test.cc
@@ -92,7 +92,7 @@ static void test_pollable_owner_fd() {
int main(int argc, char** argv) {
const char* poll_strategy = nullptr;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/fd_conservation_posix_test.cc b/test/core/iomgr/fd_conservation_posix_test.cc
index 4866e350d5..0d27b94dc2 100644
--- a/test/core/iomgr/fd_conservation_posix_test.cc
+++ b/test/core/iomgr/fd_conservation_posix_test.cc
@@ -29,7 +29,7 @@ int main(int argc, char** argv) {
struct rlimit rlim;
grpc_endpoint_pair p;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/fd_posix_test.cc b/test/core/iomgr/fd_posix_test.cc
index 4ea2389bbd..cf5ffc6354 100644
--- a/test/core/iomgr/fd_posix_test.cc
+++ b/test/core/iomgr/fd_posix_test.cc
@@ -515,7 +515,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/grpc_ipv6_loopback_available_test.cc b/test/core/iomgr/grpc_ipv6_loopback_available_test.cc
index 329aa9a851..2ef1f1978d 100644
--- a/test/core/iomgr/grpc_ipv6_loopback_available_test.cc
+++ b/test/core/iomgr/grpc_ipv6_loopback_available_test.cc
@@ -32,7 +32,7 @@
#endif
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
// This test assumes that the ipv6 loopback is available
// in all environments in which grpc tests run in.
diff --git a/test/core/iomgr/load_file_test.cc b/test/core/iomgr/load_file_test.cc
index 38c8710535..a0e0e4d7a7 100644
--- a/test/core/iomgr/load_file_test.cc
+++ b/test/core/iomgr/load_file_test.cc
@@ -152,7 +152,7 @@ static void test_load_big_file(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_load_empty_file();
test_load_failure();
diff --git a/test/core/iomgr/resolve_address_posix_test.cc b/test/core/iomgr/resolve_address_posix_test.cc
index e495e4c877..ceeb70a108 100644
--- a/test/core/iomgr/resolve_address_posix_test.cc
+++ b/test/core/iomgr/resolve_address_posix_test.cc
@@ -158,7 +158,7 @@ static void test_unix_socket_path_name_too_long(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
diff --git a/test/core/iomgr/resolve_address_test.cc b/test/core/iomgr/resolve_address_test.cc
index 8d69bab5b1..1d9e1ee27e 100644
--- a/test/core/iomgr/resolve_address_test.cc
+++ b/test/core/iomgr/resolve_address_test.cc
@@ -271,7 +271,7 @@ int main(int argc, char** argv) {
abort();
}
// Run the test.
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/resource_quota_test.cc b/test/core/iomgr/resource_quota_test.cc
index f3b35fed32..4cbc016d58 100644
--- a/test/core/iomgr/resource_quota_test.cc
+++ b/test/core/iomgr/resource_quota_test.cc
@@ -891,7 +891,7 @@ static void test_thread_maxquota_change() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
gpr_mu_init(&g_mu);
gpr_cv_init(&g_cv);
diff --git a/test/core/iomgr/sockaddr_utils_test.cc b/test/core/iomgr/sockaddr_utils_test.cc
index 3783f968b7..250d36a74a 100644
--- a/test/core/iomgr/sockaddr_utils_test.cc
+++ b/test/core/iomgr/sockaddr_utils_test.cc
@@ -270,7 +270,7 @@ static void test_sockaddr_set_get_port(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_sockaddr_is_v4mapped();
test_sockaddr_to_v4mapped();
diff --git a/test/core/iomgr/socket_utils_test.cc b/test/core/iomgr/socket_utils_test.cc
index a21f3fac62..420873734d 100644
--- a/test/core/iomgr/socket_utils_test.cc
+++ b/test/core/iomgr/socket_utils_test.cc
@@ -80,7 +80,7 @@ static const grpc_socket_mutator_vtable mutator_vtable = {
int main(int argc, char** argv) {
int sock;
grpc_error* err;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
sock = socket(PF_INET, SOCK_STREAM, 0);
GPR_ASSERT(sock > 0);
diff --git a/test/core/iomgr/tcp_client_posix_test.cc b/test/core/iomgr/tcp_client_posix_test.cc
index 90fc5aecfc..5cf3530c77 100644
--- a/test/core/iomgr/tcp_client_posix_test.cc
+++ b/test/core/iomgr/tcp_client_posix_test.cc
@@ -191,7 +191,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
diff --git a/test/core/iomgr/tcp_client_uv_test.cc b/test/core/iomgr/tcp_client_uv_test.cc
index 27f894e3f3..bde8c2f353 100644
--- a/test/core/iomgr/tcp_client_uv_test.cc
+++ b/test/core/iomgr/tcp_client_uv_test.cc
@@ -188,7 +188,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/tcp_posix_test.cc b/test/core/iomgr/tcp_posix_test.cc
index 6447cc234d..80f17a914f 100644
--- a/test/core/iomgr/tcp_posix_test.cc
+++ b/test/core/iomgr/tcp_posix_test.cc
@@ -623,7 +623,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
grpc_core::grpc_tcp_set_write_timestamps_callback(timestamps_verifier);
{
diff --git a/test/core/iomgr/tcp_server_posix_test.cc b/test/core/iomgr/tcp_server_posix_test.cc
index d646df1dae..2c66cdec77 100644
--- a/test/core/iomgr/tcp_server_posix_test.cc
+++ b/test/core/iomgr/tcp_server_posix_test.cc
@@ -437,7 +437,7 @@ int main(int argc, char** argv) {
// Zalloc dst_addrs to avoid oversized frames.
test_addrs* dst_addrs =
static_cast<test_addrs*>(gpr_zalloc(sizeof(*dst_addrs)));
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/tcp_server_uv_test.cc b/test/core/iomgr/tcp_server_uv_test.cc
index e99fa79bfd..625a18c0cc 100644
--- a/test/core/iomgr/tcp_server_uv_test.cc
+++ b/test/core/iomgr/tcp_server_uv_test.cc
@@ -288,7 +288,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
diff --git a/test/core/iomgr/time_averaged_stats_test.cc b/test/core/iomgr/time_averaged_stats_test.cc
index b932e62d1f..2923a35d1b 100644
--- a/test/core/iomgr/time_averaged_stats_test.cc
+++ b/test/core/iomgr/time_averaged_stats_test.cc
@@ -180,7 +180,7 @@ static void some_regress_some_persist_test(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
no_regress_no_persist_test_1();
no_regress_no_persist_test_2();
no_regress_no_persist_test_3();
diff --git a/test/core/iomgr/timer_heap_test.cc b/test/core/iomgr/timer_heap_test.cc
index ebe5e6610d..872cf17486 100644
--- a/test/core/iomgr/timer_heap_test.cc
+++ b/test/core/iomgr/timer_heap_test.cc
@@ -286,7 +286,7 @@ static void shrink_test(void) {
int main(int argc, char** argv) {
int i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
for (i = 0; i < 5; i++) {
test1();
diff --git a/test/core/iomgr/timer_list_test.cc b/test/core/iomgr/timer_list_test.cc
index fd65d1abf1..fa2444948b 100644
--- a/test/core/iomgr/timer_list_test.cc
+++ b/test/core/iomgr/timer_list_test.cc
@@ -221,7 +221,7 @@ void long_running_service_cleanup_test(void) {
int main(int argc, char** argv) {
/* Tests with default g_start_time */
{
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_core::ExecCtx::GlobalInit();
grpc_core::ExecCtx exec_ctx;
grpc_determine_iomgr_platform();
@@ -235,7 +235,7 @@ int main(int argc, char** argv) {
/* Begin long running service tests */
{
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
/* Set g_start_time back 25 days. */
/* We set g_start_time here in case there are any initialization
dependencies that use g_start_time. */
diff --git a/test/core/iomgr/udp_server_test.cc b/test/core/iomgr/udp_server_test.cc
index d167c0131f..f65783a017 100644
--- a/test/core/iomgr/udp_server_test.cc
+++ b/test/core/iomgr/udp_server_test.cc
@@ -360,7 +360,7 @@ static void test_receive(int number_of_clients) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
if (grpc_is_socket_reuse_port_supported()) {
g_num_listeners = 10;
diff --git a/test/core/json/json_rewrite_test.cc b/test/core/json/json_rewrite_test.cc
index 2fade12e13..b7e89cdb1a 100644
--- a/test/core/json/json_rewrite_test.cc
+++ b/test/core/json/json_rewrite_test.cc
@@ -287,7 +287,7 @@ void test_rewrites() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_rewrites();
gpr_log(GPR_INFO, "json_rewrite_test success");
return 0;
diff --git a/test/core/json/json_stream_error_test.cc b/test/core/json/json_stream_error_test.cc
index 00288d6d5e..53e20be206 100644
--- a/test/core/json/json_stream_error_test.cc
+++ b/test/core/json/json_stream_error_test.cc
@@ -49,7 +49,7 @@ static void read_error() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
read_error();
gpr_log(GPR_INFO, "json_stream_error success");
return 0;
diff --git a/test/core/json/json_test.cc b/test/core/json/json_test.cc
index 7f1dbb774a..03dd96a8ae 100644
--- a/test/core/json/json_test.cc
+++ b/test/core/json/json_test.cc
@@ -184,7 +184,7 @@ static void test_atypical() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_pairs();
test_atypical();
gpr_log(GPR_INFO, "json_test success");
diff --git a/test/core/memory_usage/BUILD b/test/core/memory_usage/BUILD
new file mode 100644
index 0000000000..f39c309e36
--- /dev/null
+++ b/test/core/memory_usage/BUILD
@@ -0,0 +1,60 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
+
+grpc_package(name = "test/core/memory_usage")
+
+licenses(["notice"]) # Apache v2
+
+grpc_cc_library(
+ name = "client",
+ testonly = 1,
+ srcs = ["client.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+grpc_cc_library(
+ name = "server",
+ testonly = 1,
+ srcs = ["server.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/core/end2end:ssl_test_data"
+ ],
+)
+
+grpc_cc_test(
+ name = "memory_usage_test",
+ srcs = ["memory_usage_test.cc"],
+ language = "C++",
+ data = [
+ ":client",
+ ":server",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/memory_usage/client.cc b/test/core/memory_usage/client.cc
index 3c3fa53b51..467586ea5f 100644
--- a/test/core/memory_usage/client.cc
+++ b/test/core/memory_usage/client.cc
@@ -193,11 +193,11 @@ int main(int argc, char** argv) {
gpr_cmdline* cl;
grpc_event event;
- grpc_init();
-
GPR_ASSERT(argc >= 1);
fake_argv[0] = argv[0];
- grpc_test_init(1, fake_argv);
+ grpc::testing::TestEnvironment env(1, fake_argv);
+
+ grpc_init();
int warmup_iterations = 100;
int benchmark_iterations = 1000;
diff --git a/test/core/memory_usage/server.cc b/test/core/memory_usage/server.cc
index 3e7bb7e11f..7424797e6f 100644
--- a/test/core/memory_usage/server.cc
+++ b/test/core/memory_usage/server.cc
@@ -162,7 +162,7 @@ int main(int argc, char** argv) {
GPR_ASSERT(argc >= 1);
fake_argv[0] = argv[0];
- grpc_test_init(1, fake_argv);
+ grpc::testing::TestEnvironment env(1, fake_argv);
grpc_init();
srand(static_cast<unsigned>(clock()));
@@ -292,9 +292,9 @@ int main(int argc, char** argv) {
send_status(&calls[k]);
}
}
+ /* fallthrough */
// no break here since we want to continue to case
// FLING_SERVER_SEND_STATUS_SNAPSHOT to destroy the snapshot call
- /* fallthrough */
case FLING_SERVER_SEND_STATUS_SNAPSHOT:
grpc_byte_buffer_destroy(payload_buffer);
grpc_byte_buffer_destroy(terminal_buffer);
diff --git a/test/core/security/auth_context_test.cc b/test/core/security/auth_context_test.cc
index 58f0d8e1c2..9a39afb800 100644
--- a/test/core/security/auth_context_test.cc
+++ b/test/core/security/auth_context_test.cc
@@ -130,7 +130,7 @@ static void test_chained_context(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_empty_context();
test_simple_context();
test_chained_context();
diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc
index 97156761bd..a7a6050ec0 100644
--- a/test/core/security/credentials_test.cc
+++ b/test/core/security/credentials_test.cc
@@ -43,6 +43,7 @@
#include "src/core/lib/security/transport/auth_filters.h"
#include "test/core/util/test_config.h"
+using grpc_core::internal::grpc_flush_cached_google_default_credentials;
using grpc_core::internal::set_gce_tenancy_checker_for_testing;
/* -- Mock channel credentials. -- */
@@ -918,6 +919,22 @@ static void test_google_default_creds_refresh_token(void) {
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
}
+static int default_creds_metadata_server_detection_httpcli_get_success_override(
+ const grpc_httpcli_request* request, grpc_millis deadline,
+ grpc_closure* on_done, grpc_httpcli_response* response) {
+ *response = http_response(200, "");
+ grpc_http_header* headers =
+ static_cast<grpc_http_header*>(gpr_malloc(sizeof(*headers) * 1));
+ headers[0].key = gpr_strdup("Metadata-Flavor");
+ headers[0].value = gpr_strdup("Google");
+ response->hdr_count = 1;
+ response->hdrs = headers;
+ GPR_ASSERT(strcmp(request->http.path, "/") == 0);
+ GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return 1;
+}
+
static char* null_well_known_creds_path_getter(void) { return nullptr; }
static bool test_gce_tenancy_checker(void) {
@@ -954,42 +971,81 @@ static void test_google_default_creds_gce(void) {
run_request_metadata_test(creds->call_creds, auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
- /* Check that we get a cached creds if we call
- grpc_google_default_credentials_create again.
- GCE detection should not occur anymore either. */
- g_test_gce_tenancy_checker_called = false;
- grpc_channel_credentials* cached_creds =
- grpc_google_default_credentials_create();
- GPR_ASSERT(cached_creds == &creds->base);
- GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
+ GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
/* Cleanup. */
- grpc_channel_credentials_unref(cached_creds);
grpc_channel_credentials_unref(&creds->base);
grpc_httpcli_set_override(nullptr, nullptr);
grpc_override_well_known_credentials_path_getter(nullptr);
}
-static void test_no_google_default_creds(void) {
+static void test_google_default_creds_non_gce(void) {
+ grpc_core::ExecCtx exec_ctx;
+ expected_md emd[] = {
+ {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
+ request_metadata_state* state =
+ make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+ grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+ nullptr, nullptr};
grpc_flush_cached_google_default_credentials();
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
grpc_override_well_known_credentials_path_getter(
null_well_known_creds_path_getter);
-
set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
g_test_gce_tenancy_checker_called = false;
g_test_is_on_gce = false;
+ /* Simulate a successful detection of metadata server. */
+ grpc_httpcli_set_override(
+ default_creds_metadata_server_detection_httpcli_get_success_override,
+ httpcli_post_should_not_be_called);
+ grpc_composite_channel_credentials* creds =
+ reinterpret_cast<grpc_composite_channel_credentials*>(
+ grpc_google_default_credentials_create());
+ /* Verify that the default creds actually embeds a GCE creds. */
+ GPR_ASSERT(creds != nullptr);
+ GPR_ASSERT(creds->call_creds != nullptr);
+ grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
+ httpcli_post_should_not_be_called);
+ run_request_metadata_test(creds->call_creds, auth_md_ctx, state);
+ grpc_core::ExecCtx::Get()->Flush();
+ GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
+ /* Cleanup. */
+ grpc_channel_credentials_unref(&creds->base);
+ grpc_httpcli_set_override(nullptr, nullptr);
+ grpc_override_well_known_credentials_path_getter(nullptr);
+}
+static int default_creds_gce_detection_httpcli_get_failure_override(
+ const grpc_httpcli_request* request, grpc_millis deadline,
+ grpc_closure* on_done, grpc_httpcli_response* response) {
+ /* No magic header. */
+ GPR_ASSERT(strcmp(request->http.path, "/") == 0);
+ GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
+ *response = http_response(200, "");
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return 1;
+}
+
+static void test_no_google_default_creds(void) {
+ grpc_flush_cached_google_default_credentials();
+ gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+ grpc_override_well_known_credentials_path_getter(
+ null_well_known_creds_path_getter);
+ set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
+ g_test_gce_tenancy_checker_called = false;
+ g_test_is_on_gce = false;
+ grpc_httpcli_set_override(
+ default_creds_gce_detection_httpcli_get_failure_override,
+ httpcli_post_should_not_be_called);
/* Simulate a successful detection of GCE. */
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
-
- /* Try a cached one. GCE detection should not occur anymore. */
+ /* Try a second one. GCE detection should occur again. */
g_test_gce_tenancy_checker_called = false;
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
- GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
-
+ GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
/* Cleanup. */
grpc_override_well_known_credentials_path_getter(nullptr);
+ grpc_httpcli_set_override(nullptr, nullptr);
}
typedef enum {
@@ -1213,7 +1269,7 @@ static void test_auth_metadata_context(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_empty_md_array();
test_add_to_empty_md_array();
@@ -1240,6 +1296,7 @@ int main(int argc, char** argv) {
test_google_default_creds_auth_key();
test_google_default_creds_refresh_token();
test_google_default_creds_gce();
+ test_google_default_creds_non_gce();
test_no_google_default_creds();
test_metadata_plugin_success();
test_metadata_plugin_failure();
diff --git a/test/core/security/json_token_test.cc b/test/core/security/json_token_test.cc
index 7a5b3355fe..a3ae18e6ab 100644
--- a/test/core/security/json_token_test.cc
+++ b/test/core/security/json_token_test.cc
@@ -482,7 +482,7 @@ static void test_parse_refresh_token_failure_no_refresh_token(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_parse_json_key_success();
test_parse_json_key_failure_bad_json();
diff --git a/test/core/security/jwt_verifier_test.cc b/test/core/security/jwt_verifier_test.cc
index 9718580a08..70155cdd06 100644
--- a/test/core/security/jwt_verifier_test.cc
+++ b/test/core/security/jwt_verifier_test.cc
@@ -600,7 +600,7 @@ static void test_jwt_verifier_bad_format(void) {
/* bad key */
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_jwt_issuer_email_domain();
test_claims_success();
diff --git a/test/core/security/linux_system_roots_test.cc b/test/core/security/linux_system_roots_test.cc
index 24d446de35..cd8bd3beb7 100644
--- a/test/core/security/linux_system_roots_test.cc
+++ b/test/core/security/linux_system_roots_test.cc
@@ -86,7 +86,7 @@ TEST(CreateRootCertsBundleTest, BundlesCorrectly) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/security/secure_endpoint_test.cc b/test/core/security/secure_endpoint_test.cc
index 23cef99dfa..f6d02895b5 100644
--- a/test/core/security/secure_endpoint_test.cc
+++ b/test/core/security/secure_endpoint_test.cc
@@ -208,7 +208,7 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
{
diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc
index fef0ea71f7..e82a8627d4 100644
--- a/test/core/security/security_connector_test.cc
+++ b/test/core/security/security_connector_test.cc
@@ -430,7 +430,7 @@ static void test_default_ssl_roots(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_unauthenticated_ssl_peer();
diff --git a/test/core/security/ssl_credentials_test.cc b/test/core/security/ssl_credentials_test.cc
index 9edcf42d3a..7c9f561665 100644
--- a/test/core/security/ssl_credentials_test.cc
+++ b/test/core/security/ssl_credentials_test.cc
@@ -56,7 +56,7 @@ static void test_convert_grpc_to_tsi_cert_pairs() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_convert_grpc_to_tsi_cert_pairs();
diff --git a/test/core/slice/b64_test.cc b/test/core/slice/b64_test.cc
index 6b29443ba1..6677150c23 100644
--- a/test/core/slice/b64_test.cc
+++ b/test/core/slice/b64_test.cc
@@ -201,7 +201,7 @@ static void test_unpadded_decode(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_simple_encode_decode_b64_no_multiline();
test_simple_encode_decode_b64_multiline();
diff --git a/test/core/slice/percent_encoding_test.cc b/test/core/slice/percent_encoding_test.cc
index e8d04fcc83..ae6c39eb26 100644
--- a/test/core/slice/percent_encoding_test.cc
+++ b/test/core/slice/percent_encoding_test.cc
@@ -118,7 +118,7 @@ static void test_nonconformant_vector(const char* encoded,
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
TEST_VECTOR(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~",
diff --git a/test/core/slice/slice_buffer_test.cc b/test/core/slice/slice_buffer_test.cc
index e59986730b..b53e3312df 100644
--- a/test/core/slice/slice_buffer_test.cc
+++ b/test/core/slice/slice_buffer_test.cc
@@ -106,7 +106,7 @@ void test_slice_buffer_move_first() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_slice_buffer_add();
diff --git a/test/core/slice/slice_hash_table_test.cc b/test/core/slice/slice_hash_table_test.cc
index 43ddfe9bf2..08cfe91e5a 100644
--- a/test/core/slice/slice_hash_table_test.cc
+++ b/test/core/slice/slice_hash_table_test.cc
@@ -217,7 +217,7 @@ TEST(SliceHashTable, CmpEmptyKeysDifferentValue) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_core::ExecCtx::GlobalInit();
int result = RUN_ALL_TESTS();
grpc_core::ExecCtx::GlobalShutdown();
diff --git a/test/core/slice/slice_string_helpers_test.cc b/test/core/slice/slice_string_helpers_test.cc
index 860a1bfe03..1bbc0947bc 100644
--- a/test/core/slice/slice_string_helpers_test.cc
+++ b/test/core/slice/slice_string_helpers_test.cc
@@ -195,7 +195,7 @@ static void test_strsplit_nospace(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_dump_slice();
test_strsplit();
test_strsplit_nospace();
diff --git a/test/core/slice/slice_test.cc b/test/core/slice/slice_test.cc
index e683c41f31..1e53a1951c 100644
--- a/test/core/slice/slice_test.cc
+++ b/test/core/slice/slice_test.cc
@@ -294,7 +294,7 @@ static void test_static_slice_copy_interning(void) {
int main(int argc, char** argv) {
unsigned length;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_slice_malloc_returns_something_sensible();
test_slice_new_returns_something_sensible();
diff --git a/test/core/slice/slice_weak_hash_table_test.cc b/test/core/slice/slice_weak_hash_table_test.cc
index b0a243d572..ab0a648727 100644
--- a/test/core/slice/slice_weak_hash_table_test.cc
+++ b/test/core/slice/slice_weak_hash_table_test.cc
@@ -98,7 +98,7 @@ TEST(SliceWeakHashTable, ForceOverload) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_core::ExecCtx::GlobalInit();
int result = RUN_ALL_TESTS();
grpc_core::ExecCtx::GlobalShutdown();
diff --git a/test/core/surface/byte_buffer_reader_test.cc b/test/core/surface/byte_buffer_reader_test.cc
index cff05caec1..301a1e283b 100644
--- a/test/core/surface/byte_buffer_reader_test.cc
+++ b/test/core/surface/byte_buffer_reader_test.cc
@@ -267,7 +267,7 @@ static void test_byte_buffer_copy(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_read_one_slice();
test_read_one_slice_malloc();
test_read_none_compressed_slice();
diff --git a/test/core/surface/channel_create_test.cc b/test/core/surface/channel_create_test.cc
index 56f4f602e8..5f109c0f84 100644
--- a/test/core/surface/channel_create_test.cc
+++ b/test/core/surface/channel_create_test.cc
@@ -44,7 +44,7 @@ void test_unknown_scheme_target(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_unknown_scheme_target();
grpc_shutdown();
diff --git a/test/core/surface/completion_queue_test.cc b/test/core/surface/completion_queue_test.cc
index f7ce8a7042..a157d75eda 100644
--- a/test/core/surface/completion_queue_test.cc
+++ b/test/core/surface/completion_queue_test.cc
@@ -440,7 +440,7 @@ struct thread_state {
};
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_no_op();
test_pollset_conversion();
diff --git a/test/core/surface/completion_queue_threading_test.cc b/test/core/surface/completion_queue_threading_test.cc
index 0b82803af6..4215aad14a 100644
--- a/test/core/surface/completion_queue_threading_test.cc
+++ b/test/core/surface/completion_queue_threading_test.cc
@@ -288,7 +288,7 @@ static void test_threading(size_t producers, size_t consumers) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_too_many_plucks();
test_threading(1, 1);
diff --git a/test/core/surface/concurrent_connectivity_test.cc b/test/core/surface/concurrent_connectivity_test.cc
index fbc5ec4c54..f606e89ac8 100644
--- a/test/core/surface/concurrent_connectivity_test.cc
+++ b/test/core/surface/concurrent_connectivity_test.cc
@@ -300,7 +300,7 @@ int run_concurrent_watches_with_short_timeouts_test() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
run_concurrent_connectivity_test();
run_concurrent_watches_with_short_timeouts_test();
diff --git a/test/core/surface/init_test.cc b/test/core/surface/init_test.cc
index 5749bc8b36..1bcd13a0b8 100644
--- a/test/core/surface/init_test.cc
+++ b/test/core/surface/init_test.cc
@@ -60,7 +60,7 @@ static void test_repeatedly() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test(1);
test(2);
test(3);
diff --git a/test/core/surface/lame_client_test.cc b/test/core/surface/lame_client_test.cc
index fac5ca8f7f..09c3d43197 100644
--- a/test/core/surface/lame_client_test.cc
+++ b/test/core/surface/lame_client_test.cc
@@ -75,7 +75,7 @@ int main(int argc, char** argv) {
grpc_slice details;
char* peer;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/surface/num_external_connectivity_watchers_test.cc b/test/core/surface/num_external_connectivity_watchers_test.cc
index 7b7a0b6dfc..454cbd5747 100644
--- a/test/core/surface/num_external_connectivity_watchers_test.cc
+++ b/test/core/surface/num_external_connectivity_watchers_test.cc
@@ -191,7 +191,7 @@ static const test_fixture secure_test = {
};
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
run_timeouts_test(&insecure_test);
run_timeouts_test(&secure_test);
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 4640b8e4ca..426ef1e8b1 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -137,6 +137,7 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable);
printf("%lx", (unsigned long) grpc_channelz_get_top_channels);
printf("%lx", (unsigned long) grpc_channelz_get_servers);
+ printf("%lx", (unsigned long) grpc_channelz_get_server);
printf("%lx", (unsigned long) grpc_channelz_get_server_sockets);
printf("%lx", (unsigned long) grpc_channelz_get_channel);
printf("%lx", (unsigned long) grpc_channelz_get_subchannel);
diff --git a/test/core/surface/secure_channel_create_test.cc b/test/core/surface/secure_channel_create_test.cc
index 06962179a2..5610d1ec4a 100644
--- a/test/core/surface/secure_channel_create_test.cc
+++ b/test/core/surface/secure_channel_create_test.cc
@@ -70,7 +70,7 @@ void test_null_creds(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_security_connector_already_in_arg();
test_null_creds();
diff --git a/test/core/surface/sequential_connectivity_test.cc b/test/core/surface/sequential_connectivity_test.cc
index 10562b3be9..3f9a7baf98 100644
--- a/test/core/surface/sequential_connectivity_test.cc
+++ b/test/core/surface/sequential_connectivity_test.cc
@@ -168,7 +168,7 @@ static const test_fixture secure_test = {
};
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
run_test(&insecure_test);
run_test(&secure_test);
diff --git a/test/core/surface/server_chttp2_test.cc b/test/core/surface/server_chttp2_test.cc
index fd8ab9cd3d..ffb7f14f98 100644
--- a/test/core/surface/server_chttp2_test.cc
+++ b/test/core/surface/server_chttp2_test.cc
@@ -67,7 +67,7 @@ void test_add_same_port_twice() {
#endif
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_unparsable_target();
#ifndef GRPC_UV
diff --git a/test/core/surface/server_test.cc b/test/core/surface/server_test.cc
index b4eabd8d4d..2fc166546b 100644
--- a/test/core/surface/server_test.cc
+++ b/test/core/surface/server_test.cc
@@ -148,7 +148,7 @@ static void test_bind_server_to_addrs(const char** addrs, size_t n) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_register_method_fail();
test_request_call_on_no_server_cq();
diff --git a/test/core/transport/bdp_estimator_test.cc b/test/core/transport/bdp_estimator_test.cc
index c7e6b2bd84..a795daaead 100644
--- a/test/core/transport/bdp_estimator_test.cc
+++ b/test/core/transport/bdp_estimator_test.cc
@@ -139,7 +139,7 @@ INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest,
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
gpr_now_impl = grpc_core::testing::fake_gpr_now;
grpc_init();
grpc_timer_manager_set_threading(false);
diff --git a/test/core/transport/byte_stream_test.cc b/test/core/transport/byte_stream_test.cc
index df09637249..6c543892d0 100644
--- a/test/core/transport/byte_stream_test.cc
+++ b/test/core/transport/byte_stream_test.cc
@@ -245,7 +245,7 @@ TEST(CachingByteStream, SharedCache) {
int main(int argc, char** argv) {
grpc_init();
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int retval = RUN_ALL_TESTS();
grpc_shutdown();
diff --git a/test/core/transport/chttp2/BUILD b/test/core/transport/chttp2/BUILD
index 6eff716b01..33437373e4 100644
--- a/test/core/transport/chttp2/BUILD
+++ b/test/core/transport/chttp2/BUILD
@@ -67,6 +67,22 @@ grpc_cc_test(
)
grpc_cc_test(
+ name = "context_list_test",
+ srcs = ["context_list_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+
+grpc_cc_test(
name = "hpack_encoder_test",
srcs = ["hpack_encoder_test.cc"],
language = "C++",
diff --git a/test/core/transport/chttp2/alpn_test.cc b/test/core/transport/chttp2/alpn_test.cc
index a43377393e..6da5299363 100644
--- a/test/core/transport/chttp2/alpn_test.cc
+++ b/test/core/transport/chttp2/alpn_test.cc
@@ -49,7 +49,7 @@ static void test_alpn_grpc_before_h2(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_alpn_success();
test_alpn_failure();
test_alpn_grpc_before_h2();
diff --git a/test/core/transport/chttp2/context_list_test.cc b/test/core/transport/chttp2/context_list_test.cc
new file mode 100644
index 0000000000..edbe658a89
--- /dev/null
+++ b/test/core/transport/chttp2/context_list_test.cc
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <gtest/gtest.h>
+#include <new>
+#include <vector>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/context_list.h"
+#include "src/core/lib/transport/transport.h"
+#include "test/core/util/mock_endpoint.h"
+#include "test/core/util/test_config.h"
+
+#include <grpc/grpc.h>
+
+namespace grpc_core {
+namespace testing {
+namespace {
+
+const uint32_t kByteOffset = 123;
+
+void TestExecuteFlushesListVerifier(void* arg, grpc_core::Timestamps* ts) {
+ ASSERT_NE(arg, nullptr);
+ EXPECT_EQ(ts->byte_offset, kByteOffset);
+ gpr_atm* done = reinterpret_cast<gpr_atm*>(arg);
+ gpr_atm_rel_store(done, static_cast<gpr_atm>(1));
+}
+
+void discard_write(grpc_slice slice) {}
+
+/** Tests that all ContextList elements in the list are flushed out on
+ * execute.
+ * Also tests that arg and byte_counter are passed correctly.
+ */
+TEST(ContextList, ExecuteFlushesList) {
+ grpc_core::ContextList* list = nullptr;
+ grpc_http2_set_write_timestamps_callback(TestExecuteFlushesListVerifier);
+ const int kNumElems = 5;
+ grpc_core::ExecCtx exec_ctx;
+ grpc_stream_refcount ref;
+ GRPC_STREAM_REF_INIT(&ref, 1, nullptr, nullptr, "dummy ref");
+ grpc_resource_quota* resource_quota =
+ grpc_resource_quota_create("context_list_test");
+ grpc_endpoint* mock_endpoint =
+ grpc_mock_endpoint_create(discard_write, resource_quota);
+ grpc_transport* t =
+ grpc_create_chttp2_transport(nullptr, mock_endpoint, true);
+ std::vector<grpc_chttp2_stream*> s;
+ s.reserve(kNumElems);
+ gpr_atm verifier_called[kNumElems];
+ for (auto i = 0; i < kNumElems; i++) {
+ s.push_back(static_cast<grpc_chttp2_stream*>(
+ gpr_malloc(grpc_transport_stream_size(t))));
+ grpc_transport_init_stream(reinterpret_cast<grpc_transport*>(t),
+ reinterpret_cast<grpc_stream*>(s[i]), &ref,
+ nullptr, nullptr);
+ s[i]->context = &verifier_called[i];
+ s[i]->byte_counter = kByteOffset;
+ gpr_atm_rel_store(&verifier_called[i], static_cast<gpr_atm>(0));
+ grpc_core::ContextList::Append(&list, s[i]);
+ }
+ grpc_core::Timestamps ts;
+ grpc_core::ContextList::Execute(list, &ts, GRPC_ERROR_NONE);
+ for (auto i = 0; i < kNumElems; i++) {
+ EXPECT_EQ(gpr_atm_acq_load(&verifier_called[i]), static_cast<gpr_atm>(1));
+ grpc_transport_destroy_stream(reinterpret_cast<grpc_transport*>(t),
+ reinterpret_cast<grpc_stream*>(s[i]),
+ nullptr);
+ exec_ctx.Flush();
+ gpr_free(s[i]);
+ }
+ grpc_transport_destroy(t);
+ grpc_resource_quota_unref(resource_quota);
+ exec_ctx.Flush();
+}
+} // namespace
+} // namespace testing
+} // namespace grpc_core
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ grpc_init();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/core/transport/chttp2/hpack_encoder_test.cc b/test/core/transport/chttp2/hpack_encoder_test.cc
index ab819f9092..6cbc914c7f 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.cc
+++ b/test/core/transport/chttp2/hpack_encoder_test.cc
@@ -261,7 +261,7 @@ static void run_test(void (*test)(), const char* name) {
int main(int argc, char** argv) {
size_t i;
grpc_test_only_set_slice_hash_seed(0);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
TEST(test_basic_headers);
TEST(test_decode_table_overflow);
diff --git a/test/core/transport/chttp2/hpack_parser_test.cc b/test/core/transport/chttp2/hpack_parser_test.cc
index 43b6c79e8a..882ad726b5 100644
--- a/test/core/transport/chttp2/hpack_parser_test.cc
+++ b/test/core/transport/chttp2/hpack_parser_test.cc
@@ -208,7 +208,7 @@ static void test_vectors(grpc_slice_split_mode mode) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_vectors(GRPC_SLICE_SPLIT_MERGE_ALL);
test_vectors(GRPC_SLICE_SPLIT_ONE_BYTE);
diff --git a/test/core/transport/chttp2/hpack_table_test.cc b/test/core/transport/chttp2/hpack_table_test.cc
index 3ab463b631..c31975786f 100644
--- a/test/core/transport/chttp2/hpack_table_test.cc
+++ b/test/core/transport/chttp2/hpack_table_test.cc
@@ -268,7 +268,7 @@ static void test_find(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_static_lookup();
test_many_additions();
diff --git a/test/core/transport/chttp2/settings_timeout_test.cc b/test/core/transport/chttp2/settings_timeout_test.cc
index 2d6f0a9a62..a9789edbf2 100644
--- a/test/core/transport/chttp2/settings_timeout_test.cc
+++ b/test/core/transport/chttp2/settings_timeout_test.cc
@@ -248,7 +248,7 @@ TEST(SettingsTimeout, Basic) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
int result = RUN_ALL_TESTS();
grpc_shutdown();
diff --git a/test/core/transport/chttp2/stream_map_test.cc b/test/core/transport/chttp2/stream_map_test.cc
index 773eb3a35f..a36c496eb1 100644
--- a/test/core/transport/chttp2/stream_map_test.cc
+++ b/test/core/transport/chttp2/stream_map_test.cc
@@ -193,7 +193,7 @@ int main(int argc, char** argv) {
uint32_t prev = 1;
uint32_t tmp;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_no_op();
test_empty_find();
diff --git a/test/core/transport/chttp2/varint_test.cc b/test/core/transport/chttp2/varint_test.cc
index 36760d0c72..5e00cc376a 100644
--- a/test/core/transport/chttp2/varint_test.cc
+++ b/test/core/transport/chttp2/varint_test.cc
@@ -44,7 +44,7 @@ static void test_varint(uint32_t value, uint32_t prefix_bits, uint8_t prefix_or,
test_varint(value, prefix_bits, prefix_or, expect, sizeof(expect) - 1)
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
TEST_VARINT(0, 1, 0, "\x00");
TEST_VARINT(128, 1, 0, "\x7f\x01");
diff --git a/test/core/transport/connectivity_state_test.cc b/test/core/transport/connectivity_state_test.cc
index cbd6318f52..7c7e3084bf 100644
--- a/test/core/transport/connectivity_state_test.cc
+++ b/test/core/transport/connectivity_state_test.cc
@@ -134,7 +134,7 @@ static void test_subscribe_with_failure_then_destroy(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
grpc_core::testing::grpc_tracer_enable_flag(&grpc_connectivity_state_trace);
test_connectivity_state_name();
diff --git a/test/core/transport/metadata_test.cc b/test/core/transport/metadata_test.cc
index 8ab9639dfa..9a49d28ccc 100644
--- a/test/core/transport/metadata_test.cc
+++ b/test/core/transport/metadata_test.cc
@@ -370,7 +370,7 @@ static void test_copied_static_metadata(bool dup_key, bool dup_value) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_no_op();
for (int k = 0; k <= 1; k++) {
diff --git a/test/core/transport/pid_controller_test.cc b/test/core/transport/pid_controller_test.cc
index 8d2cec4042..f6235244f6 100644
--- a/test/core/transport/pid_controller_test.cc
+++ b/test/core/transport/pid_controller_test.cc
@@ -85,7 +85,7 @@ INSTANTIATE_TEST_CASE_P(
} // namespace grpc_core
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/core/transport/status_conversion_test.cc b/test/core/transport/status_conversion_test.cc
index f7b3c62a40..949be42aeb 100644
--- a/test/core/transport/status_conversion_test.cc
+++ b/test/core/transport/status_conversion_test.cc
@@ -163,7 +163,7 @@ static void test_http2_status_to_grpc_status() {
int main(int argc, char** argv) {
int i;
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_grpc_status_to_http2_error();
diff --git a/test/core/transport/stream_owned_slice_test.cc b/test/core/transport/stream_owned_slice_test.cc
index 7831f67a04..48a77db9a5 100644
--- a/test/core/transport/stream_owned_slice_test.cc
+++ b/test/core/transport/stream_owned_slice_test.cc
@@ -26,7 +26,7 @@
static void do_nothing(void* arg, grpc_error* error) {}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
uint8_t buffer[] = "abc123";
diff --git a/test/core/transport/timeout_encoding_test.cc b/test/core/transport/timeout_encoding_test.cc
index b7044b5b41..22e68fe554 100644
--- a/test/core/transport/timeout_encoding_test.cc
+++ b/test/core/transport/timeout_encoding_test.cc
@@ -156,7 +156,7 @@ void test_decoding_fails(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_encoding();
test_decoding();
test_decoding_fails();
diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
index c8d88aa72c..9a4541bb7d 100644
--- a/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
+++ b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
@@ -19,14 +19,14 @@
#include <grpc/grpc.h>
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
-#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h"
#include "src/core/tsi/transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
#define ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME "Hello Google"
-#define ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL "lame"
#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME "bigtable.google.api.com"
#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1 "A@google.com"
#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2 "B@google.com"
@@ -37,37 +37,22 @@ const size_t kMaxRpcVersionMinor = 2;
const size_t kMinRpcVersionMajor = 2;
const size_t kMinRpcVersionMinor = 1;
+using grpc_core::internal::alts_handshaker_client_get_closure_for_testing;
+using grpc_core::internal::
+ alts_handshaker_client_get_initial_metadata_for_testing;
+using grpc_core::internal::
+ alts_handshaker_client_get_recv_buffer_addr_for_testing;
+using grpc_core::internal::alts_handshaker_client_get_send_buffer_for_testing;
using grpc_core::internal::alts_handshaker_client_set_grpc_caller_for_testing;
typedef struct alts_handshaker_client_test_config {
grpc_channel* channel;
grpc_completion_queue* cq;
alts_handshaker_client* client;
+ alts_handshaker_client* server;
grpc_slice out_frame;
} alts_handshaker_client_test_config;
-static alts_tsi_event* alts_tsi_event_create_for_testing(bool is_client) {
- alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e)));
- grpc_metadata_array_init(&e->initial_metadata);
- grpc_metadata_array_init(&e->trailing_metadata);
- e->options = is_client ? grpc_alts_credentials_client_options_create()
- : grpc_alts_credentials_server_options_create();
- if (is_client) {
- grpc_alts_credentials_client_options_add_target_service_account(
- e->options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1);
- grpc_alts_credentials_client_options_add_target_service_account(
- e->options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2);
- }
- grpc_gcp_rpc_protocol_versions* versions = &e->options->rpc_versions;
- GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
- versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
- GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
- versions, kMinRpcVersionMajor, kMinRpcVersionMinor));
- e->target_name =
- grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME);
- return e;
-}
-
static void validate_rpc_protocol_versions(
grpc_gcp_rpc_protocol_versions* versions) {
GPR_ASSERT(versions != nullptr);
@@ -101,11 +86,11 @@ static void validate_target_identities(
/**
* Validate if grpc operation data is correctly populated with the fields of
- * ALTS TSI event.
+ * ALTS handshaker client.
*/
-static bool validate_op(alts_tsi_event* event, const grpc_op* op, size_t nops,
- bool is_start) {
- GPR_ASSERT(event != nullptr && op != nullptr && nops != 0);
+static bool validate_op(alts_handshaker_client* c, const grpc_op* op,
+ size_t nops, bool is_start) {
+ GPR_ASSERT(c != nullptr && op != nullptr && nops != 0);
bool ok = true;
grpc_op* start_op = const_cast<grpc_op*>(op);
if (is_start) {
@@ -113,23 +98,22 @@ static bool validate_op(alts_tsi_event* event, const grpc_op* op, size_t nops,
ok &= (op->data.send_initial_metadata.count == 0);
op++;
GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
-
ok &= (op->op == GRPC_OP_RECV_INITIAL_METADATA);
ok &= (op->data.recv_initial_metadata.recv_initial_metadata ==
- &event->initial_metadata);
+ alts_handshaker_client_get_initial_metadata_for_testing(c));
op++;
GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
}
ok &= (op->op == GRPC_OP_SEND_MESSAGE);
- ok &= (op->data.send_message.send_message == event->send_buffer);
+ ok &= (op->data.send_message.send_message ==
+ alts_handshaker_client_get_send_buffer_for_testing(c));
op++;
GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
-
ok &= (op->op == GRPC_OP_RECV_MESSAGE);
- ok &= (op->data.recv_message.recv_message == &event->recv_buffer);
+ ok &= (op->data.recv_message.recv_message ==
+ alts_handshaker_client_get_recv_buffer_addr_for_testing(c));
op++;
GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
-
return ok;
}
@@ -152,7 +136,7 @@ static grpc_gcp_handshaker_req* deserialize_handshaker_req(
*/
static grpc_call_error check_must_not_be_called(grpc_call* call,
const grpc_op* ops, size_t nops,
- void* tag) {
+ grpc_closure* tag) {
GPR_ASSERT(0);
}
@@ -164,10 +148,14 @@ static grpc_call_error check_must_not_be_called(grpc_call* call,
*/
static grpc_call_error check_client_start_success(grpc_call* call,
const grpc_op* op,
- size_t nops, void* tag) {
- alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
- grpc_gcp_handshaker_req* req =
- deserialize_handshaker_req(CLIENT_START_REQ, event->send_buffer);
+ size_t nops,
+ grpc_closure* closure) {
+ alts_handshaker_client* client =
+ static_cast<alts_handshaker_client*>(closure->cb_arg);
+ GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
+ grpc_gcp_handshaker_req* req = deserialize_handshaker_req(
+ CLIENT_START_REQ,
+ alts_handshaker_client_get_send_buffer_for_testing(client));
GPR_ASSERT(req->client_start.handshake_security_protocol ==
grpc_gcp_HandshakeProtocol_ALTS);
const void* data = (static_cast<repeated_field*>(
@@ -194,7 +182,7 @@ static grpc_call_error check_client_start_success(grpc_call* call,
GRPC_SLICE_LENGTH(*target_name)) == 0);
GPR_ASSERT(GRPC_SLICE_LENGTH(*target_name) ==
strlen(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME));
- GPR_ASSERT(validate_op(event, op, nops, true /* is_start */));
+ GPR_ASSERT(validate_op(client, op, nops, true /* is_start */));
grpc_gcp_handshaker_req_destroy(req);
return GRPC_CALL_OK;
}
@@ -207,10 +195,14 @@ static grpc_call_error check_client_start_success(grpc_call* call,
*/
static grpc_call_error check_server_start_success(grpc_call* call,
const grpc_op* op,
- size_t nops, void* tag) {
- alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
- grpc_gcp_handshaker_req* req =
- deserialize_handshaker_req(SERVER_START_REQ, event->send_buffer);
+ size_t nops,
+ grpc_closure* closure) {
+ alts_handshaker_client* client =
+ static_cast<alts_handshaker_client*>(closure->cb_arg);
+ GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
+ grpc_gcp_handshaker_req* req = deserialize_handshaker_req(
+ SERVER_START_REQ,
+ alts_handshaker_client_get_send_buffer_for_testing(client));
const void* data = (static_cast<repeated_field*>(
req->server_start.application_protocols.arg))
->data;
@@ -231,7 +223,7 @@ static grpc_call_error check_server_start_success(grpc_call* call,
ALTS_RECORD_PROTOCOL,
GRPC_SLICE_LENGTH(*record_protocol)) == 0);
validate_rpc_protocol_versions(&req->server_start.rpc_versions);
- GPR_ASSERT(validate_op(event, op, nops, true /* is_start */));
+ GPR_ASSERT(validate_op(client, op, nops, true /* is_start */));
grpc_gcp_handshaker_req_destroy(req);
return GRPC_CALL_OK;
}
@@ -242,16 +234,18 @@ static grpc_call_error check_server_start_success(grpc_call* call,
* and op is correctly populated.
*/
static grpc_call_error check_next_success(grpc_call* call, const grpc_op* op,
- size_t nops, void* tag) {
- alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
- grpc_gcp_handshaker_req* req =
- deserialize_handshaker_req(NEXT_REQ, event->send_buffer);
+ size_t nops, grpc_closure* closure) {
+ alts_handshaker_client* client =
+ static_cast<alts_handshaker_client*>(closure->cb_arg);
+ GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure);
+ grpc_gcp_handshaker_req* req = deserialize_handshaker_req(
+ NEXT_REQ, alts_handshaker_client_get_send_buffer_for_testing(client));
grpc_slice* in_bytes = static_cast<grpc_slice*>(req->next.in_bytes.arg);
GPR_ASSERT(in_bytes != nullptr);
GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*in_bytes),
ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME,
GRPC_SLICE_LENGTH(*in_bytes)) == 0);
- GPR_ASSERT(validate_op(event, op, nops, false /* is_start */));
+ GPR_ASSERT(validate_op(client, op, nops, false /* is_start */));
grpc_gcp_handshaker_req_destroy(req);
return GRPC_CALL_OK;
}
@@ -262,21 +256,54 @@ static grpc_call_error check_next_success(grpc_call* call, const grpc_op* op,
*/
static grpc_call_error check_grpc_call_failure(grpc_call* call,
const grpc_op* op, size_t nops,
- void* tag) {
+ grpc_closure* tag) {
return GRPC_CALL_ERROR;
}
+static grpc_alts_credentials_options* create_credentials_options(
+ bool is_client) {
+ grpc_alts_credentials_options* options =
+ is_client ? grpc_alts_credentials_client_options_create()
+ : grpc_alts_credentials_server_options_create();
+ if (is_client) {
+ grpc_alts_credentials_client_options_add_target_service_account(
+ options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1);
+ grpc_alts_credentials_client_options_add_target_service_account(
+ options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2);
+ }
+ grpc_gcp_rpc_protocol_versions* versions = &options->rpc_versions;
+ GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
+ versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
+ GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
+ versions, kMinRpcVersionMajor, kMinRpcVersionMinor));
+ return options;
+}
+
static alts_handshaker_client_test_config* create_config() {
alts_handshaker_client_test_config* config =
static_cast<alts_handshaker_client_test_config*>(
gpr_zalloc(sizeof(*config)));
config->channel = grpc_insecure_channel_create(
- ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL, nullptr, nullptr);
+ ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, nullptr, nullptr);
config->cq = grpc_completion_queue_create_for_next(nullptr);
+ grpc_alts_credentials_options* client_options =
+ create_credentials_options(true /* is_client */);
+ grpc_alts_credentials_options* server_options =
+ create_credentials_options(false /* is_client */);
+ config->server = alts_grpc_handshaker_client_create(
+ nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING,
+ nullptr, server_options,
+ grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME),
+ nullptr, nullptr, nullptr, nullptr, false);
config->client = alts_grpc_handshaker_client_create(
- config->channel, config->cq,
- ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL);
+ nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING,
+ nullptr, client_options,
+ grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME),
+ nullptr, nullptr, nullptr, nullptr, true);
GPR_ASSERT(config->client != nullptr);
+ GPR_ASSERT(config->server != nullptr);
+ grpc_alts_credentials_options_destroy(client_options);
+ grpc_alts_credentials_options_destroy(server_options);
config->out_frame =
grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME);
return config;
@@ -289,6 +316,7 @@ static void destroy_config(alts_handshaker_client_test_config* config) {
grpc_completion_queue_destroy(config->cq);
grpc_channel_destroy(config->channel);
alts_handshaker_client_destroy(config->client);
+ alts_handshaker_client_destroy(config->server);
grpc_slice_unref(config->out_frame);
gpr_free(config);
}
@@ -296,73 +324,50 @@ static void destroy_config(alts_handshaker_client_test_config* config) {
static void schedule_request_invalid_arg_test() {
/* Initialization. */
alts_handshaker_client_test_config* config = create_config();
- alts_tsi_event* event = nullptr;
-
/* Tests. */
alts_handshaker_client_set_grpc_caller_for_testing(config->client,
check_must_not_be_called);
- event = alts_tsi_event_create_for_testing(true /* is_client */);
/* Check client_start. */
- GPR_ASSERT(alts_handshaker_client_start_client(nullptr, event) ==
- TSI_INVALID_ARGUMENT);
- GPR_ASSERT(alts_handshaker_client_start_client(config->client, nullptr) ==
+ GPR_ASSERT(alts_handshaker_client_start_client(nullptr) ==
TSI_INVALID_ARGUMENT);
-
/* Check server_start. */
- GPR_ASSERT(alts_handshaker_client_start_server(
- config->client, event, nullptr) == TSI_INVALID_ARGUMENT);
- GPR_ASSERT(alts_handshaker_client_start_server(config->client, nullptr,
- &config->out_frame) ==
+ GPR_ASSERT(alts_handshaker_client_start_server(config->server, nullptr) ==
TSI_INVALID_ARGUMENT);
- GPR_ASSERT(alts_handshaker_client_start_server(
- nullptr, event, &config->out_frame) == TSI_INVALID_ARGUMENT);
-
- /* Check next. */
- GPR_ASSERT(alts_handshaker_client_next(config->client, event, nullptr) ==
+ GPR_ASSERT(alts_handshaker_client_start_server(nullptr, &config->out_frame) ==
TSI_INVALID_ARGUMENT);
- GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr,
- &config->out_frame) ==
+ /* Check next. */
+ GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr) ==
TSI_INVALID_ARGUMENT);
- GPR_ASSERT(alts_handshaker_client_next(nullptr, event, &config->out_frame) ==
+ GPR_ASSERT(alts_handshaker_client_next(nullptr, &config->out_frame) ==
TSI_INVALID_ARGUMENT);
-
/* Check shutdown. */
alts_handshaker_client_shutdown(nullptr);
-
/* Cleanup. */
- alts_tsi_event_destroy(event);
destroy_config(config);
}
static void schedule_request_success_test() {
/* Initialization. */
alts_handshaker_client_test_config* config = create_config();
- alts_tsi_event* event = nullptr;
-
/* Check client_start success. */
alts_handshaker_client_set_grpc_caller_for_testing(
config->client, check_client_start_success);
- event = alts_tsi_event_create_for_testing(true /* is_client. */);
- GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) ==
- TSI_OK);
- alts_tsi_event_destroy(event);
-
+ GPR_ASSERT(alts_handshaker_client_start_client(config->client) == TSI_OK);
/* Check server_start success. */
alts_handshaker_client_set_grpc_caller_for_testing(
- config->client, check_server_start_success);
- event = alts_tsi_event_create_for_testing(false /* is_client. */);
- GPR_ASSERT(alts_handshaker_client_start_server(config->client, event,
+ config->server, check_server_start_success);
+ GPR_ASSERT(alts_handshaker_client_start_server(config->server,
&config->out_frame) == TSI_OK);
- alts_tsi_event_destroy(event);
-
- /* Check next success. */
+ /* Check client next success. */
alts_handshaker_client_set_grpc_caller_for_testing(config->client,
check_next_success);
- event = alts_tsi_event_create_for_testing(true /* is_client. */);
- GPR_ASSERT(alts_handshaker_client_next(config->client, event,
- &config->out_frame) == TSI_OK);
- alts_tsi_event_destroy(event);
-
+ GPR_ASSERT(alts_handshaker_client_next(config->client, &config->out_frame) ==
+ TSI_OK);
+ /* Check server next success. */
+ alts_handshaker_client_set_grpc_caller_for_testing(config->server,
+ check_next_success);
+ GPR_ASSERT(alts_handshaker_client_next(config->server, &config->out_frame) ==
+ TSI_OK);
/* Cleanup. */
destroy_config(config);
}
@@ -370,30 +375,22 @@ static void schedule_request_success_test() {
static void schedule_request_grpc_call_failure_test() {
/* Initialization. */
alts_handshaker_client_test_config* config = create_config();
- alts_tsi_event* event = nullptr;
-
/* Check client_start failure. */
alts_handshaker_client_set_grpc_caller_for_testing(config->client,
check_grpc_call_failure);
- event = alts_tsi_event_create_for_testing(true /* is_client. */);
- GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) ==
+ GPR_ASSERT(alts_handshaker_client_start_client(config->client) ==
TSI_INTERNAL_ERROR);
- alts_tsi_event_destroy(event);
-
/* Check server_start failure. */
- event = alts_tsi_event_create_for_testing(false /* is_client. */);
- GPR_ASSERT(alts_handshaker_client_start_server(config->client, event,
- &config->out_frame) ==
+ alts_handshaker_client_set_grpc_caller_for_testing(config->server,
+ check_grpc_call_failure);
+ GPR_ASSERT(alts_handshaker_client_start_server(
+ config->server, &config->out_frame) == TSI_INTERNAL_ERROR);
+ /* Check client next failure. */
+ GPR_ASSERT(alts_handshaker_client_next(config->client, &config->out_frame) ==
+ TSI_INTERNAL_ERROR);
+ /* Check server next failure. */
+ GPR_ASSERT(alts_handshaker_client_next(config->server, &config->out_frame) ==
TSI_INTERNAL_ERROR);
- alts_tsi_event_destroy(event);
-
- /* Check next failure. */
- event = alts_tsi_event_create_for_testing(true /* is_cleint. */);
- GPR_ASSERT(
- alts_handshaker_client_next(config->client, event, &config->out_frame) ==
- TSI_INTERNAL_ERROR);
- alts_tsi_event_destroy(event);
-
/* Cleanup. */
destroy_config(config);
}
@@ -401,13 +398,13 @@ static void schedule_request_grpc_call_failure_test() {
int main(int argc, char** argv) {
/* Initialization. */
grpc_init();
-
+ grpc_alts_shared_resource_dedicated_init();
/* Tests. */
schedule_request_invalid_arg_test();
schedule_request_success_test();
schedule_request_grpc_call_failure_test();
-
/* Cleanup. */
+ grpc_alts_shared_resource_dedicated_shutdown();
grpc_shutdown();
return 0;
}
diff --git a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
index e9eb7e175f..316ff13816 100644
--- a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
+++ b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
@@ -24,7 +24,7 @@
#include "src/core/lib/gprpp/thd.h"
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
-#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h"
#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
@@ -43,12 +43,18 @@
#define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MAJOR 2
#define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MINOR 1
+using grpc_core::internal::alts_handshaker_client_check_fields_for_testing;
+using grpc_core::internal::alts_handshaker_client_get_handshaker_for_testing;
using grpc_core::internal::
- alts_tsi_handshaker_get_has_sent_start_message_for_testing;
+ alts_handshaker_client_get_recv_buffer_addr_for_testing;
+using grpc_core::internal::alts_handshaker_client_set_cb_for_testing;
+using grpc_core::internal::alts_handshaker_client_set_fields_for_testing;
+using grpc_core::internal::alts_handshaker_client_set_recv_bytes_for_testing;
+using grpc_core::internal::alts_handshaker_client_set_vtable_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_get_client_for_testing;
using grpc_core::internal::alts_tsi_handshaker_get_is_client_for_testing;
-using grpc_core::internal::alts_tsi_handshaker_get_recv_bytes_for_testing;
-using grpc_core::internal::alts_tsi_handshaker_set_client_for_testing;
-using grpc_core::internal::alts_tsi_handshaker_set_recv_bytes_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_set_client_vtable_for_testing;
+static bool should_handshaker_client_api_succeed = true;
/* ALTS mock notification. */
typedef struct notification {
@@ -57,12 +63,6 @@ typedef struct notification {
bool notified;
} notification;
-/* ALTS mock handshaker client. */
-typedef struct alts_mock_handshaker_client {
- alts_handshaker_client base;
- bool used_for_success_test;
-} alts_mock_handshaker_client;
-
/* Type of ALTS handshaker response. */
typedef enum {
INVALID,
@@ -73,10 +73,7 @@ typedef enum {
SERVER_NEXT,
} alts_handshaker_response_type;
-static alts_tsi_event* client_start_event;
-static alts_tsi_event* client_next_event;
-static alts_tsi_event* server_start_event;
-static alts_tsi_event* server_next_event;
+static alts_handshaker_client* cb_event = nullptr;
static notification caller_to_tsi_notification;
static notification tsi_to_caller_notification;
@@ -311,89 +308,69 @@ static void on_server_next_success_cb(tsi_result status, void* user_data,
signal(&tsi_to_caller_notification);
}
-static tsi_result mock_client_start(alts_handshaker_client* self,
- alts_tsi_event* event) {
- alts_mock_handshaker_client* client =
- reinterpret_cast<alts_mock_handshaker_client*>(self);
- if (!client->used_for_success_test) {
- alts_tsi_event_destroy(event);
+static tsi_result mock_client_start(alts_handshaker_client* client) {
+ if (!should_handshaker_client_api_succeed) {
return TSI_INTERNAL_ERROR;
}
- GPR_ASSERT(event->cb == on_client_start_success_cb);
- GPR_ASSERT(event->user_data == nullptr);
- GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing(
- event->handshaker));
+ alts_handshaker_client_check_fields_for_testing(
+ client, on_client_start_success_cb, nullptr, false, nullptr);
/* Populate handshaker response for client_start request. */
- event->recv_buffer = generate_handshaker_response(CLIENT_START);
- client_start_event = event;
+ grpc_byte_buffer** recv_buffer_ptr =
+ alts_handshaker_client_get_recv_buffer_addr_for_testing(client);
+ *recv_buffer_ptr = generate_handshaker_response(CLIENT_START);
+ cb_event = client;
signal(&caller_to_tsi_notification);
return TSI_OK;
}
static void mock_shutdown(alts_handshaker_client* self) {}
-static tsi_result mock_server_start(alts_handshaker_client* self,
- alts_tsi_event* event,
+static tsi_result mock_server_start(alts_handshaker_client* client,
grpc_slice* bytes_received) {
- alts_mock_handshaker_client* client =
- reinterpret_cast<alts_mock_handshaker_client*>(self);
- if (!client->used_for_success_test) {
- alts_tsi_event_destroy(event);
+ if (!should_handshaker_client_api_succeed) {
return TSI_INTERNAL_ERROR;
}
- GPR_ASSERT(event->cb == on_server_start_success_cb);
- GPR_ASSERT(event->user_data == nullptr);
+ alts_handshaker_client_check_fields_for_testing(
+ client, on_server_start_success_cb, nullptr, false, nullptr);
grpc_slice slice = grpc_empty_slice();
GPR_ASSERT(grpc_slice_cmp(*bytes_received, slice) == 0);
- GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing(
- event->handshaker));
/* Populate handshaker response for server_start request. */
- event->recv_buffer = generate_handshaker_response(SERVER_START);
- server_start_event = event;
+ grpc_byte_buffer** recv_buffer_ptr =
+ alts_handshaker_client_get_recv_buffer_addr_for_testing(client);
+ *recv_buffer_ptr = generate_handshaker_response(SERVER_START);
+ cb_event = client;
grpc_slice_unref(slice);
signal(&caller_to_tsi_notification);
return TSI_OK;
}
-static tsi_result mock_next(alts_handshaker_client* self, alts_tsi_event* event,
+static tsi_result mock_next(alts_handshaker_client* client,
grpc_slice* bytes_received) {
- alts_mock_handshaker_client* client =
- reinterpret_cast<alts_mock_handshaker_client*>(self);
- if (!client->used_for_success_test) {
- alts_tsi_event_destroy(event);
+ if (!should_handshaker_client_api_succeed) {
return TSI_INTERNAL_ERROR;
}
- bool is_client =
- alts_tsi_handshaker_get_is_client_for_testing(event->handshaker);
- if (is_client) {
- GPR_ASSERT(event->cb == on_client_next_success_cb);
- } else {
- GPR_ASSERT(event->cb == on_server_next_success_cb);
- }
- GPR_ASSERT(event->user_data == nullptr);
+ alts_tsi_handshaker* handshaker =
+ alts_handshaker_client_get_handshaker_for_testing(client);
+ bool is_client = alts_tsi_handshaker_get_is_client_for_testing(handshaker);
+ tsi_handshaker_on_next_done_cb cb =
+ is_client ? on_client_next_success_cb : on_server_next_success_cb;
+ alts_handshaker_client_set_cb_for_testing(client, cb);
+ alts_handshaker_client_set_recv_bytes_for_testing(client, bytes_received);
+ alts_handshaker_client_check_fields_for_testing(client, cb, nullptr, true,
+ bytes_received);
GPR_ASSERT(bytes_received != nullptr);
GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*bytes_received),
ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
GRPC_SLICE_LENGTH(*bytes_received)) == 0);
- GPR_ASSERT(grpc_slice_cmp(alts_tsi_handshaker_get_recv_bytes_for_testing(
- event->handshaker),
- *bytes_received) == 0);
- GPR_ASSERT(alts_tsi_handshaker_get_has_sent_start_message_for_testing(
- event->handshaker));
/* Populate handshaker response for next request. */
grpc_slice out_frame =
grpc_slice_from_static_string(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME);
- if (is_client) {
- event->recv_buffer = generate_handshaker_response(CLIENT_NEXT);
- } else {
- event->recv_buffer = generate_handshaker_response(SERVER_NEXT);
- }
- alts_tsi_handshaker_set_recv_bytes_for_testing(event->handshaker, &out_frame);
- if (is_client) {
- client_next_event = event;
- } else {
- server_next_event = event;
- }
+ grpc_byte_buffer** recv_buffer_ptr =
+ alts_handshaker_client_get_recv_buffer_addr_for_testing(client);
+ *recv_buffer_ptr = is_client ? generate_handshaker_response(CLIENT_NEXT)
+ : generate_handshaker_response(SERVER_NEXT);
+ alts_handshaker_client_set_recv_bytes_for_testing(client, &out_frame);
+ cb_event = client;
signal(&caller_to_tsi_notification);
grpc_slice_unref(out_frame);
return TSI_OK;
@@ -401,38 +378,27 @@ static tsi_result mock_next(alts_handshaker_client* self, alts_tsi_event* event,
static void mock_destruct(alts_handshaker_client* client) {}
-static const alts_handshaker_client_vtable vtable = {
- mock_client_start, mock_server_start, mock_next, mock_shutdown,
- mock_destruct};
-
-static alts_handshaker_client* alts_mock_handshaker_client_create(
- bool used_for_success_test) {
- alts_mock_handshaker_client* client =
- static_cast<alts_mock_handshaker_client*>(gpr_zalloc(sizeof(*client)));
- client->base.vtable = &vtable;
- client->used_for_success_test = used_for_success_test;
- return &client->base;
-}
+static alts_handshaker_client_vtable vtable = {mock_client_start,
+ mock_server_start, mock_next,
+ mock_shutdown, mock_destruct};
-static tsi_handshaker* create_test_handshaker(bool used_for_success_test,
- bool is_client) {
+static tsi_handshaker* create_test_handshaker(bool is_client) {
tsi_handshaker* handshaker = nullptr;
- alts_handshaker_client* client =
- alts_mock_handshaker_client_create(used_for_success_test);
grpc_alts_credentials_options* options =
grpc_alts_credentials_client_options_create();
- alts_tsi_handshaker_create(options, "target_name", "lame", is_client, nullptr,
- &handshaker);
+ alts_tsi_handshaker_create(options, "target_name",
+ ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, is_client,
+ nullptr, &handshaker);
alts_tsi_handshaker* alts_handshaker =
reinterpret_cast<alts_tsi_handshaker*>(handshaker);
- alts_tsi_handshaker_set_client_for_testing(alts_handshaker, client);
+ alts_tsi_handshaker_set_client_vtable_for_testing(alts_handshaker, &vtable);
grpc_alts_credentials_options_destroy(options);
return handshaker;
}
static void check_handshaker_next_invalid_input() {
/* Initialization. */
- tsi_handshaker* handshaker = create_test_handshaker(true, true);
+ tsi_handshaker* handshaker = create_test_handshaker(true);
/* Check nullptr handshaker. */
GPR_ASSERT(tsi_handshaker_next(nullptr, nullptr, 0, nullptr, nullptr, nullptr,
check_must_not_be_called,
@@ -447,8 +413,7 @@ static void check_handshaker_next_invalid_input() {
static void check_handshaker_shutdown_invalid_input() {
/* Initialization. */
- tsi_handshaker* handshaker = create_test_handshaker(
- false /* used_for_success_test */, true /* is_client */);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */);
/* Check nullptr handshaker. */
tsi_handshaker_shutdown(nullptr);
/* Cleanup. */
@@ -460,10 +425,10 @@ static void check_handshaker_next_success() {
* Create handshakers for which internal mock client is going to do
* correctness check.
*/
- tsi_handshaker* client_handshaker = create_test_handshaker(
- true /* used_for_success_test */, true /* is_client */);
- tsi_handshaker* server_handshaker = create_test_handshaker(
- true /* used_for_success_test */, false /* is_client */);
+ tsi_handshaker* client_handshaker =
+ create_test_handshaker(true /* is_client */);
+ tsi_handshaker* server_handshaker =
+ create_test_handshaker(false /* is_client */);
/* Client start. */
GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr,
nullptr, nullptr, on_client_start_success_cb,
@@ -494,9 +459,7 @@ static void check_handshaker_next_success() {
}
static void check_handshaker_next_with_shutdown() {
- /* Initialization. */
- tsi_handshaker* handshaker = create_test_handshaker(
- true /* used_for_success_test */, true /* is_client*/);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client*/);
/* next(success) -- shutdown(success) -- next (fail) */
GPR_ASSERT(tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr,
nullptr, on_client_start_success_cb,
@@ -514,20 +477,18 @@ static void check_handshaker_next_with_shutdown() {
}
static void check_handle_response_with_shutdown(void* unused) {
- /* Client start. */
wait(&caller_to_tsi_notification);
- alts_tsi_event_dispatch_to_handshaker(client_start_event, true /* is_ok */);
- alts_tsi_event_destroy(client_start_event);
+ alts_handshaker_client_handle_response(cb_event, true /* is_ok */);
}
static void check_handshaker_next_failure() {
/**
* Create handshakers for which internal mock client is always going to fail.
*/
- tsi_handshaker* client_handshaker = create_test_handshaker(
- false /* used_for_success_test */, true /* is_client */);
- tsi_handshaker* server_handshaker = create_test_handshaker(
- false /* used_for_success_test */, false /* is_client */);
+ tsi_handshaker* client_handshaker =
+ create_test_handshaker(true /* is_client */);
+ tsi_handshaker* server_handshaker =
+ create_test_handshaker(false /* is_client */);
/* Client start. */
GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr,
nullptr, nullptr, check_must_not_be_called,
@@ -578,34 +539,46 @@ static void on_failed_grpc_call_cb(tsi_result status, void* user_data,
}
static void check_handle_response_invalid_input() {
+ /* Initialization. */
+ notification_init(&caller_to_tsi_notification);
+ notification_init(&tsi_to_caller_notification);
/**
* Create a handshaker at the client side, for which internal mock client is
* always going to fail.
*/
- tsi_handshaker* handshaker = create_test_handshaker(
- false /* used_for_success_test */, true /* is_client */);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */);
+ tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr,
+ on_client_start_success_cb, nullptr);
alts_tsi_handshaker* alts_handshaker =
reinterpret_cast<alts_tsi_handshaker*>(handshaker);
- grpc_byte_buffer recv_buffer;
+ grpc_slice slice = grpc_empty_slice();
+ grpc_byte_buffer* recv_buffer = grpc_raw_byte_buffer_create(&slice, 1);
+ alts_handshaker_client* client =
+ alts_tsi_handshaker_get_client_for_testing(alts_handshaker);
/* Check nullptr handshaker. */
- alts_tsi_handshaker_handle_response(nullptr, &recv_buffer, GRPC_STATUS_OK,
- nullptr, on_invalid_input_cb, nullptr,
- true);
+ alts_handshaker_client_set_fields_for_testing(client, nullptr,
+ on_invalid_input_cb, nullptr,
+ recv_buffer, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, true);
/* Check nullptr recv_bytes. */
- alts_tsi_handshaker_handle_response(alts_handshaker, nullptr, GRPC_STATUS_OK,
- nullptr, on_invalid_input_cb, nullptr,
- true);
+ alts_handshaker_client_set_fields_for_testing(client, alts_handshaker,
+ on_invalid_input_cb, nullptr,
+ nullptr, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, true);
/* Check failed grpc call made to handshaker service. */
- alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer,
- GRPC_STATUS_UNKNOWN, nullptr,
- on_failed_grpc_call_cb, nullptr, true);
-
- alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer,
- GRPC_STATUS_OK, nullptr,
- on_failed_grpc_call_cb, nullptr, false);
-
+ alts_handshaker_client_set_fields_for_testing(
+ client, alts_handshaker, on_failed_grpc_call_cb, nullptr, recv_buffer,
+ GRPC_STATUS_UNKNOWN);
+ alts_handshaker_client_handle_response(client, true);
+ alts_handshaker_client_set_fields_for_testing(client, alts_handshaker,
+ on_failed_grpc_call_cb, nullptr,
+ recv_buffer, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, false);
/* Cleanup. */
+ grpc_slice_unref(slice);
tsi_handshaker_destroy(handshaker);
+ notification_destroy(&caller_to_tsi_notification);
+ notification_destroy(&tsi_to_caller_notification);
}
static void on_invalid_resp_cb(tsi_result status, void* user_data,
@@ -620,41 +593,45 @@ static void on_invalid_resp_cb(tsi_result status, void* user_data,
}
static void check_handle_response_invalid_resp() {
+ /* Initialization. */
+ notification_init(&caller_to_tsi_notification);
+ notification_init(&tsi_to_caller_notification);
/**
* Create a handshaker at the client side, for which internal mock client is
* always going to fail.
*/
- tsi_handshaker* handshaker = create_test_handshaker(
- false /* used_for_success_test */, true /* is_client */);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */);
+ tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr,
+ on_client_start_success_cb, nullptr);
alts_tsi_handshaker* alts_handshaker =
reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+ alts_handshaker_client* client =
+ alts_tsi_handshaker_get_client_for_testing(alts_handshaker);
/* Tests. */
grpc_byte_buffer* recv_buffer = generate_handshaker_response(INVALID);
- alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer,
- GRPC_STATUS_OK, nullptr,
- on_invalid_resp_cb, nullptr, true);
+ alts_handshaker_client_set_fields_for_testing(client, alts_handshaker,
+ on_invalid_resp_cb, nullptr,
+ recv_buffer, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, true);
/* Cleanup. */
- grpc_byte_buffer_destroy(recv_buffer);
tsi_handshaker_destroy(handshaker);
+ notification_destroy(&caller_to_tsi_notification);
+ notification_destroy(&tsi_to_caller_notification);
}
static void check_handle_response_success(void* unused) {
/* Client start. */
wait(&caller_to_tsi_notification);
- alts_tsi_event_dispatch_to_handshaker(client_start_event, true /* is_ok */);
- alts_tsi_event_destroy(client_start_event);
+ alts_handshaker_client_handle_response(cb_event, true /* is_ok */);
/* Client next. */
wait(&caller_to_tsi_notification);
- alts_tsi_event_dispatch_to_handshaker(client_next_event, true /* is_ok */);
- alts_tsi_event_destroy(client_next_event);
+ alts_handshaker_client_handle_response(cb_event, true /* is_ok */);
/* Server start. */
wait(&caller_to_tsi_notification);
- alts_tsi_event_dispatch_to_handshaker(server_start_event, true /* is_ok */);
- alts_tsi_event_destroy(server_start_event);
+ alts_handshaker_client_handle_response(cb_event, true /* is_ok */);
/* Server next. */
wait(&caller_to_tsi_notification);
- alts_tsi_event_dispatch_to_handshaker(server_next_event, true /* is_ok */);
- alts_tsi_event_destroy(server_next_event);
+ alts_handshaker_client_handle_response(cb_event, true /* is_ok */);
}
static void on_failed_resp_cb(tsi_result status, void* user_data,
@@ -669,22 +646,30 @@ static void on_failed_resp_cb(tsi_result status, void* user_data,
}
static void check_handle_response_failure() {
+ /* Initialization. */
+ notification_init(&caller_to_tsi_notification);
+ notification_init(&tsi_to_caller_notification);
/**
* Create a handshaker at the client side, for which internal mock client is
* always going to fail.
*/
- tsi_handshaker* handshaker = create_test_handshaker(
- false /* used_for_success_test */, true /* is_client */);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */);
+ tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr,
+ on_client_start_success_cb, nullptr);
alts_tsi_handshaker* alts_handshaker =
reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+ alts_handshaker_client* client =
+ alts_tsi_handshaker_get_client_for_testing(alts_handshaker);
/* Tests. */
grpc_byte_buffer* recv_buffer = generate_handshaker_response(FAILED);
- alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer,
- GRPC_STATUS_OK, nullptr,
- on_failed_resp_cb, nullptr, true);
- grpc_byte_buffer_destroy(recv_buffer);
+ alts_handshaker_client_set_fields_for_testing(client, alts_handshaker,
+ on_failed_resp_cb, nullptr,
+ recv_buffer, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, true /* is_ok*/);
/* Cleanup. */
tsi_handshaker_destroy(handshaker);
+ notification_destroy(&caller_to_tsi_notification);
+ notification_destroy(&tsi_to_caller_notification);
}
static void on_shutdown_resp_cb(tsi_result status, void* user_data,
@@ -699,26 +684,38 @@ static void on_shutdown_resp_cb(tsi_result status, void* user_data,
}
static void check_handle_response_after_shutdown() {
- tsi_handshaker* handshaker = create_test_handshaker(
- true /* used_for_success_test */, true /* is_client */);
+ /* Initialization. */
+ notification_init(&caller_to_tsi_notification);
+ notification_init(&tsi_to_caller_notification);
+ tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */);
+ tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr,
+ on_client_start_success_cb, nullptr);
alts_tsi_handshaker* alts_handshaker =
reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+ alts_handshaker_client* client =
+ alts_tsi_handshaker_get_client_for_testing(alts_handshaker);
+ grpc_byte_buffer** recv_buffer_ptr =
+ alts_handshaker_client_get_recv_buffer_addr_for_testing(client);
+ grpc_byte_buffer_destroy(*recv_buffer_ptr);
+
/* Tests. */
tsi_handshaker_shutdown(handshaker);
grpc_byte_buffer* recv_buffer = generate_handshaker_response(CLIENT_START);
- alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer,
- GRPC_STATUS_OK, nullptr,
- on_shutdown_resp_cb, nullptr, true);
- grpc_byte_buffer_destroy(recv_buffer);
+ alts_handshaker_client_set_fields_for_testing(client, alts_handshaker,
+ on_shutdown_resp_cb, nullptr,
+ recv_buffer, GRPC_STATUS_OK);
+ alts_handshaker_client_handle_response(client, true);
/* Cleanup. */
tsi_handshaker_destroy(handshaker);
+ notification_destroy(&caller_to_tsi_notification);
+ notification_destroy(&tsi_to_caller_notification);
}
void check_handshaker_next_fails_after_shutdown() {
/* Initialization. */
notification_init(&caller_to_tsi_notification);
notification_init(&tsi_to_caller_notification);
- client_start_event = nullptr;
+ cb_event = nullptr;
/* Tests. */
grpc_core::Thread thd("alts_tsi_handshaker_test",
&check_handle_response_with_shutdown, nullptr);
@@ -734,10 +731,6 @@ void check_handshaker_success() {
/* Initialization. */
notification_init(&caller_to_tsi_notification);
notification_init(&tsi_to_caller_notification);
- client_start_event = nullptr;
- client_next_event = nullptr;
- server_start_event = nullptr;
- server_next_event = nullptr;
/* Tests. */
grpc_core::Thread thd("alts_tsi_handshaker_test",
&check_handle_response_success, nullptr);
@@ -752,17 +745,21 @@ void check_handshaker_success() {
int main(int argc, char** argv) {
/* Initialization. */
grpc_init();
+ grpc_alts_shared_resource_dedicated_init();
/* Tests. */
+ should_handshaker_client_api_succeed = true;
check_handshaker_success();
check_handshaker_next_invalid_input();
- check_handshaker_shutdown_invalid_input();
check_handshaker_next_fails_after_shutdown();
+ check_handle_response_after_shutdown();
+ should_handshaker_client_api_succeed = false;
+ check_handshaker_shutdown_invalid_input();
check_handshaker_next_failure();
check_handle_response_invalid_input();
check_handle_response_invalid_resp();
check_handle_response_failure();
- check_handle_response_after_shutdown();
/* Cleanup. */
+ grpc_alts_shared_resource_dedicated_shutdown();
grpc_shutdown();
return 0;
}
diff --git a/test/core/tsi/fake_transport_security_test.cc b/test/core/tsi/fake_transport_security_test.cc
index 587d8f5dda..32361f19d3 100644
--- a/test/core/tsi/fake_transport_security_test.cc
+++ b/test/core/tsi/fake_transport_security_test.cc
@@ -139,7 +139,7 @@ void fake_tsi_test_do_round_trip_odd_buffer_size() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
fake_tsi_test_do_handshake_tiny_handshake_buffer();
fake_tsi_test_do_handshake_small_handshake_buffer();
diff --git a/test/core/tsi/ssl_session_cache_test.cc b/test/core/tsi/ssl_session_cache_test.cc
index c86cefb3ff..b9c98c0b57 100644
--- a/test/core/tsi/ssl_session_cache_test.cc
+++ b/test/core/tsi/ssl_session_cache_test.cc
@@ -145,7 +145,7 @@ TEST(SslSessionCacheTest, LruCache) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc
index baffad6ea3..fc6c6ba320 100644
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -777,7 +777,7 @@ void ssl_tsi_test_handshaker_factory_internals() {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
ssl_tsi_test_do_handshake_tiny_handshake_buffer();
diff --git a/test/core/tsi/transport_security_test.cc b/test/core/tsi/transport_security_test.cc
index 5c92912f6f..150e5745a8 100644
--- a/test/core/tsi/transport_security_test.cc
+++ b/test/core/tsi/transport_security_test.cc
@@ -381,7 +381,7 @@ static void test_handshaker_invalid_state(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_peer_matches_name();
test_result_strings();
test_protector_invalid_args();
diff --git a/test/core/util/cmdline_test.cc b/test/core/util/cmdline_test.cc
index 9f5ad88d57..59e1bbff34 100644
--- a/test/core/util/cmdline_test.cc
+++ b/test/core/util/cmdline_test.cc
@@ -463,7 +463,7 @@ static void test_badargs4(void) {
}
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
test_simple_int();
test_eq_int();
test_2dash_int();
diff --git a/test/core/util/fuzzer_corpus_test.cc b/test/core/util/fuzzer_corpus_test.cc
index ebf1913137..6e3785c4f7 100644
--- a/test/core/util/fuzzer_corpus_test.cc
+++ b/test/core/util/fuzzer_corpus_test.cc
@@ -144,7 +144,7 @@ INSTANTIATE_TEST_CASE_P(
::testing::internal::ParamGenerator<std::string>(new ExampleGenerator));
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
ParseCommandLineFlags(&argc, &argv, true);
::testing::InitGoogleTest(&argc, argv);
diff --git a/test/core/util/mock_endpoint.cc b/test/core/util/mock_endpoint.cc
index ef6fd62b51..e5867cd526 100644
--- a/test/core/util/mock_endpoint.cc
+++ b/test/core/util/mock_endpoint.cc
@@ -103,18 +103,19 @@ static grpc_resource_user* me_get_resource_user(grpc_endpoint* ep) {
static int me_get_fd(grpc_endpoint* ep) { return -1; }
-static const grpc_endpoint_vtable vtable = {
- me_read,
- me_write,
- me_add_to_pollset,
- me_add_to_pollset_set,
- me_delete_from_pollset_set,
- me_shutdown,
- me_destroy,
- me_get_resource_user,
- me_get_peer,
- me_get_fd,
-};
+static bool me_can_track_err(grpc_endpoint* ep) { return false; }
+
+static const grpc_endpoint_vtable vtable = {me_read,
+ me_write,
+ me_add_to_pollset,
+ me_add_to_pollset_set,
+ me_delete_from_pollset_set,
+ me_shutdown,
+ me_destroy,
+ me_get_resource_user,
+ me_get_peer,
+ me_get_fd,
+ me_can_track_err};
grpc_endpoint* grpc_mock_endpoint_create(void (*on_write)(grpc_slice slice),
grpc_resource_quota* resource_quota) {
diff --git a/test/core/util/passthru_endpoint.cc b/test/core/util/passthru_endpoint.cc
index 3cc8ad6fe1..51b6de4695 100644
--- a/test/core/util/passthru_endpoint.cc
+++ b/test/core/util/passthru_endpoint.cc
@@ -155,6 +155,8 @@ static char* me_get_peer(grpc_endpoint* ep) {
static int me_get_fd(grpc_endpoint* ep) { return -1; }
+static bool me_can_track_err(grpc_endpoint* ep) { return false; }
+
static grpc_resource_user* me_get_resource_user(grpc_endpoint* ep) {
half* m = reinterpret_cast<half*>(ep);
return m->resource_user;
@@ -171,6 +173,7 @@ static const grpc_endpoint_vtable vtable = {
me_get_resource_user,
me_get_peer,
me_get_fd,
+ me_can_track_err,
};
static void half_init(half* m, passthru_endpoint* parent,
diff --git a/test/core/util/test_config.cc b/test/core/util/test_config.cc
index 6a0d444a73..fe80bb2d4d 100644
--- a/test/core/util/test_config.cc
+++ b/test/core/util/test_config.cc
@@ -397,3 +397,15 @@ void grpc_test_init(int argc, char** argv) {
concurrently running test binary */
srand(seed());
}
+
+namespace grpc {
+namespace testing {
+
+TestEnvironment::TestEnvironment(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+}
+
+TestEnvironment::~TestEnvironment() {}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 5b3d34799e..112af3176f 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -37,6 +37,21 @@ gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms);
#define GRPC_TEST_PICK_PORT
#endif
+// Prefer TestEnvironment below.
void grpc_test_init(int argc, char** argv);
+namespace grpc {
+namespace testing {
+
+// A TestEnvironment object should be alive in the main function of a test. It
+// provides test init and shutdown inside.
+class TestEnvironment {
+ public:
+ TestEnvironment(int argc, char** argv);
+ ~TestEnvironment();
+};
+
+} // namespace testing
+} // namespace grpc
+
#endif /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
diff --git a/test/core/util/trickle_endpoint.cc b/test/core/util/trickle_endpoint.cc
index 62ed72a629..b0da735e57 100644
--- a/test/core/util/trickle_endpoint.cc
+++ b/test/core/util/trickle_endpoint.cc
@@ -131,6 +131,8 @@ static int te_get_fd(grpc_endpoint* ep) {
return grpc_endpoint_get_fd(te->wrapped);
}
+static bool te_can_track_err(grpc_endpoint* ep) { return false; }
+
static void te_finish_write(void* arg, grpc_error* error) {
trickle_endpoint* te = static_cast<trickle_endpoint*>(arg);
gpr_mu_lock(&te->mu);
@@ -148,7 +150,8 @@ static const grpc_endpoint_vtable vtable = {te_read,
te_destroy,
te_get_resource_user,
te_get_peer,
- te_get_fd};
+ te_get_fd,
+ te_can_track_err};
grpc_endpoint* grpc_trickle_endpoint_create(grpc_endpoint* wrap,
double bytes_per_second) {
diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc
index 976eeb6aea..bf321d8a89 100644
--- a/test/cpp/client/client_channel_stress_test.cc
+++ b/test/cpp/client/client_channel_stress_test.cc
@@ -321,7 +321,7 @@ class ClientChannelStressTest {
int main(int argc, char** argv) {
grpc_init();
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
grpc::testing::ClientChannelStressTest test;
test.Run();
grpc_shutdown();
diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden
index 93e1e68654..1871e1375e 100644
--- a/test/cpp/codegen/compiler_test_golden
+++ b/test/cpp/codegen/compiler_test_golden
@@ -30,9 +30,11 @@
#include <grpcpp/impl/codegen/async_generic_service.h>
#include <grpcpp/impl/codegen/async_stream.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
+#include <grpcpp/impl/codegen/client_callback.h>
#include <grpcpp/impl/codegen/method_handler_impl.h>
#include <grpcpp/impl/codegen/proto_utils.h>
#include <grpcpp/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/codegen/server_callback.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/stub_options.h>
@@ -116,10 +118,13 @@ class ServiceA final {
//
// Method A2 leading comment 1
// Method A2 leading comment 2
+ virtual void MethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::experimental::ClientWriteReactor< ::grpc::testing::Request>* reactor) = 0;
// MethodA2 trailing comment 1
// Method A3 leading comment 1
+ virtual void MethodA3(::grpc::ClientContext* context, ::grpc::testing::Request* request, ::grpc::experimental::ClientReadReactor< ::grpc::testing::Response>* reactor) = 0;
// Method A3 trailing comment 1
// Method A4 leading comment 1
+ virtual void MethodA4(::grpc::ClientContext* context, ::grpc::experimental::ClientBidiReactor< ::grpc::testing::Request,::grpc::testing::Response>* reactor) = 0;
// Method A4 trailing comment 1
};
virtual class experimental_async_interface* experimental_async() { return nullptr; }
@@ -177,6 +182,9 @@ class ServiceA final {
public StubInterface::experimental_async_interface {
public:
void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
+ void MethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::experimental::ClientWriteReactor< ::grpc::testing::Request>* reactor) override;
+ void MethodA3(::grpc::ClientContext* context, ::grpc::testing::Request* request, ::grpc::experimental::ClientReadReactor< ::grpc::testing::Response>* reactor) override;
+ void MethodA4(::grpc::ClientContext* context, ::grpc::experimental::ClientBidiReactor< ::grpc::testing::Request,::grpc::testing::Response>* reactor) override;
private:
friend class Stub;
explicit experimental_async(Stub* stub): stub_(stub) { }
@@ -308,6 +316,98 @@ class ServiceA final {
};
typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<WithAsyncMethod_MethodA3<WithAsyncMethod_MethodA4<Service > > > > AsyncService;
template <class BaseClass>
+ class ExperimentalWithCallbackMethod_MethodA1 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithCallbackMethod_MethodA1() {
+ ::grpc::Service::experimental().MarkMethodCallback(0,
+ new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
+ [this](::grpc::ServerContext* context,
+ const ::grpc::testing::Request* request,
+ ::grpc::testing::Response* response,
+ ::grpc::experimental::ServerCallbackRpcController* controller) {
+ return this->MethodA1(context, request, response, controller);
+ }));
+ }
+ ~ExperimentalWithCallbackMethod_MethodA1() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual void MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); }
+ };
+ template <class BaseClass>
+ class ExperimentalWithCallbackMethod_MethodA2 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithCallbackMethod_MethodA2() {
+ ::grpc::Service::experimental().MarkMethodCallback(1,
+ new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
+ [this] { return this->MethodA2(); }));
+ }
+ ~ExperimentalWithCallbackMethod_MethodA2() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA2() {
+ return new ::grpc::internal::UnimplementedReadReactor<
+ ::grpc::testing::Request, ::grpc::testing::Response>;}
+ };
+ template <class BaseClass>
+ class ExperimentalWithCallbackMethod_MethodA3 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithCallbackMethod_MethodA3() {
+ ::grpc::Service::experimental().MarkMethodCallback(2,
+ new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
+ [this] { return this->MethodA3(); }));
+ }
+ ~ExperimentalWithCallbackMethod_MethodA3() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA3() {
+ return new ::grpc::internal::UnimplementedWriteReactor<
+ ::grpc::testing::Request, ::grpc::testing::Response>;}
+ };
+ template <class BaseClass>
+ class ExperimentalWithCallbackMethod_MethodA4 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithCallbackMethod_MethodA4() {
+ ::grpc::Service::experimental().MarkMethodCallback(3,
+ new ::grpc::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
+ [this] { return this->MethodA4(); }));
+ }
+ ~ExperimentalWithCallbackMethod_MethodA4() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4() {
+ return new ::grpc::internal::UnimplementedBidiReactor<
+ ::grpc::testing::Request, ::grpc::testing::Response>;}
+ };
+ typedef ExperimentalWithCallbackMethod_MethodA1<ExperimentalWithCallbackMethod_MethodA2<ExperimentalWithCallbackMethod_MethodA3<ExperimentalWithCallbackMethod_MethodA4<Service > > > > ExperimentalCallbackService;
+ template <class BaseClass>
class WithGenericMethod_MethodA1 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
@@ -456,6 +556,97 @@ class ServiceA final {
}
};
template <class BaseClass>
+ class ExperimentalWithRawCallbackMethod_MethodA1 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithRawCallbackMethod_MethodA1() {
+ ::grpc::Service::experimental().MarkMethodRawCallback(0,
+ new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+ [this](::grpc::ServerContext* context,
+ const ::grpc::ByteBuffer* request,
+ ::grpc::ByteBuffer* response,
+ ::grpc::experimental::ServerCallbackRpcController* controller) {
+ this->MethodA1(context, request, response, controller);
+ }));
+ }
+ ~ExperimentalWithRawCallbackMethod_MethodA1() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual void MethodA1(::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); }
+ };
+ template <class BaseClass>
+ class ExperimentalWithRawCallbackMethod_MethodA2 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithRawCallbackMethod_MethodA2() {
+ ::grpc::Service::experimental().MarkMethodRawCallback(1,
+ new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+ [this] { return this->MethodA2(); }));
+ }
+ ~ExperimentalWithRawCallbackMethod_MethodA2() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA2() {
+ return new ::grpc::internal::UnimplementedReadReactor<
+ ::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
+ };
+ template <class BaseClass>
+ class ExperimentalWithRawCallbackMethod_MethodA3 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithRawCallbackMethod_MethodA3() {
+ ::grpc::Service::experimental().MarkMethodRawCallback(2,
+ new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+ [this] { return this->MethodA3(); }));
+ }
+ ~ExperimentalWithRawCallbackMethod_MethodA3() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA3() {
+ return new ::grpc::internal::UnimplementedWriteReactor<
+ ::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
+ };
+ template <class BaseClass>
+ class ExperimentalWithRawCallbackMethod_MethodA4 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithRawCallbackMethod_MethodA4() {
+ ::grpc::Service::experimental().MarkMethodRawCallback(3,
+ new ::grpc::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+ [this] { return this->MethodA4(); }));
+ }
+ ~ExperimentalWithRawCallbackMethod_MethodA4() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual ::grpc::experimental::ServerBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA4() {
+ return new ::grpc::internal::UnimplementedBidiReactor<
+ ::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
+ };
+ template <class BaseClass>
class WithStreamedUnaryMethod_MethodA1 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
@@ -591,6 +782,32 @@ class ServiceB final {
};
typedef WithAsyncMethod_MethodB1<Service > AsyncService;
template <class BaseClass>
+ class ExperimentalWithCallbackMethod_MethodB1 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithCallbackMethod_MethodB1() {
+ ::grpc::Service::experimental().MarkMethodCallback(0,
+ new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
+ [this](::grpc::ServerContext* context,
+ const ::grpc::testing::Request* request,
+ ::grpc::testing::Response* response,
+ ::grpc::experimental::ServerCallbackRpcController* controller) {
+ return this->MethodB1(context, request, response, controller);
+ }));
+ }
+ ~ExperimentalWithCallbackMethod_MethodB1() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual void MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); }
+ };
+ typedef ExperimentalWithCallbackMethod_MethodB1<Service > ExperimentalCallbackService;
+ template <class BaseClass>
class WithGenericMethod_MethodB1 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
@@ -628,6 +845,31 @@ class ServiceB final {
}
};
template <class BaseClass>
+ class ExperimentalWithRawCallbackMethod_MethodB1 : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ ExperimentalWithRawCallbackMethod_MethodB1() {
+ ::grpc::Service::experimental().MarkMethodRawCallback(0,
+ new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+ [this](::grpc::ServerContext* context,
+ const ::grpc::ByteBuffer* request,
+ ::grpc::ByteBuffer* response,
+ ::grpc::experimental::ServerCallbackRpcController* controller) {
+ this->MethodB1(context, request, response, controller);
+ }));
+ }
+ ~ExperimentalWithRawCallbackMethod_MethodB1() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ virtual void MethodB1(::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); }
+ };
+ template <class BaseClass>
class WithStreamedUnaryMethod_MethodB1 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_test.cc
index e909d03658..802cdc209a 100644
--- a/test/cpp/common/alarm_test.cc
+++ b/test/cpp/common/alarm_test.cc
@@ -313,7 +313,7 @@ TEST(AlarmTest, UnsetDestruction) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index 0415efc1ef..eb600ffb17 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -35,6 +35,32 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "test_health_check_service_impl",
+ testonly = True,
+ srcs = ["test_health_check_service_impl.cc"],
+ hdrs = ["test_health_check_service_impl.h"],
+ deps = [
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/health/v1:health_proto",
+ ],
+)
+
+grpc_cc_library(
+ name = "interceptors_util",
+ testonly = True,
+ srcs = ["interceptors_util.cc"],
+ hdrs = ["interceptors_util.h"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/cpp/util:test_util",
+ ],
+)
+
grpc_cc_test(
name = "async_end2end_test",
srcs = ["async_end2end_test.cc"],
@@ -110,6 +136,27 @@ grpc_cc_test(
"//:grpc",
"//:grpc++",
"//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:simple_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+grpc_cc_test(
+ name = "client_interceptors_end2end_test",
+ srcs = ["client_interceptors_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":interceptors_util",
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
@@ -125,6 +172,7 @@ grpc_cc_library(
"gtest",
],
deps = [
+ ":interceptors_util",
":test_service_impl",
"//:gpr",
"//:grpc",
@@ -247,6 +295,7 @@ grpc_cc_test(
"gtest",
],
deps = [
+ ":test_health_check_service_impl",
":test_service_impl",
"//:gpr",
"//:grpc",
@@ -470,6 +519,26 @@ grpc_cc_binary(
)
grpc_cc_test(
+ name = "server_interceptors_end2end_test",
+ srcs = ["server_interceptors_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":interceptors_util",
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+grpc_cc_test(
name = "server_load_reporting_end2end_test",
srcs = ["server_load_reporting_end2end_test.cc"],
external_deps = [
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 6ecb957801..e09f54dcc3 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -1884,7 +1884,7 @@ int main(int argc, char** argv) {
// Change the backup poll interval from 5s to 100ms to speed up the
// ReconnectChannel test
gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "100");
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc
index 7a7a716e79..29b59e4e5e 100644
--- a/test/cpp/end2end/channelz_service_test.cc
+++ b/test/cpp/end2end/channelz_service_test.cc
@@ -41,6 +41,8 @@
using grpc::channelz::v1::GetChannelRequest;
using grpc::channelz::v1::GetChannelResponse;
+using grpc::channelz::v1::GetServerRequest;
+using grpc::channelz::v1::GetServerResponse;
using grpc::channelz::v1::GetServerSocketsRequest;
using grpc::channelz::v1::GetServerSocketsResponse;
using grpc::channelz::v1::GetServersRequest;
@@ -460,6 +462,29 @@ TEST_F(ChannelzServerTest, BasicServerTest) {
EXPECT_EQ(response.server_size(), 1);
}
+TEST_F(ChannelzServerTest, BasicGetServerTest) {
+ ResetStubs();
+ ConfigureProxy(1);
+ GetServersRequest get_servers_request;
+ GetServersResponse get_servers_response;
+ get_servers_request.set_start_server_id(0);
+ ClientContext get_servers_context;
+ Status s = channelz_stub_->GetServers(
+ &get_servers_context, get_servers_request, &get_servers_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_servers_response.server_size(), 1);
+ GetServerRequest get_server_request;
+ GetServerResponse get_server_response;
+ get_server_request.set_server_id(
+ get_servers_response.server(0).ref().server_id());
+ ClientContext get_server_context;
+ s = channelz_stub_->GetServer(&get_server_context, get_server_request,
+ &get_server_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_servers_response.server(0).ref().server_id(),
+ get_server_response.server().ref().server_id());
+}
+
TEST_F(ChannelzServerTest, ServerCallTest) {
ResetStubs();
ConfigureProxy(1);
@@ -626,11 +651,33 @@ TEST_F(ChannelzServerTest, GetServerSocketsTest) {
EXPECT_EQ(get_server_sockets_response.socket_ref_size(), 1);
}
+TEST_F(ChannelzServerTest, GetServerListenSocketsTest) {
+ ResetStubs();
+ ConfigureProxy(1);
+ GetServersRequest get_server_request;
+ GetServersResponse get_server_response;
+ get_server_request.set_start_server_id(0);
+ ClientContext get_server_context;
+ Status s = channelz_stub_->GetServers(&get_server_context, get_server_request,
+ &get_server_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_server_response.server_size(), 1);
+ EXPECT_EQ(get_server_response.server(0).listen_socket_size(), 1);
+ GetSocketRequest get_socket_request;
+ GetSocketResponse get_socket_response;
+ get_socket_request.set_socket_id(
+ get_server_response.server(0).listen_socket(0).socket_id());
+ ClientContext get_socket_context;
+ s = channelz_stub_->GetSocket(&get_socket_context, get_socket_request,
+ &get_socket_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+}
+
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/client_callback_end2end_test.cc b/test/cpp/end2end/client_callback_end2end_test.cc
index 62a85641c7..a999321992 100644
--- a/test/cpp/end2end/client_callback_end2end_test.cc
+++ b/test/cpp/end2end/client_callback_end2end_test.cc
@@ -34,6 +34,7 @@
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
#include "test/cpp/util/byte_buffer_proto_helper.h"
+#include "test/cpp/util/string_ref_helper.h"
#include <gtest/gtest.h>
@@ -41,13 +42,38 @@ namespace grpc {
namespace testing {
namespace {
-class ClientCallbackEnd2endTest : public ::testing::Test {
+class TestScenario {
+ public:
+ TestScenario(bool serve_callback) : callback_server(serve_callback) {}
+ void Log() const;
+ bool callback_server;
+};
+
+static std::ostream& operator<<(std::ostream& out,
+ const TestScenario& scenario) {
+ return out << "TestScenario{callback_server="
+ << (scenario.callback_server ? "true" : "false") << "}";
+}
+
+void TestScenario::Log() const {
+ std::ostringstream out;
+ out << *this;
+ gpr_log(GPR_DEBUG, "%s", out.str().c_str());
+}
+
+class ClientCallbackEnd2endTest
+ : public ::testing::TestWithParam<TestScenario> {
protected:
- ClientCallbackEnd2endTest() {}
+ ClientCallbackEnd2endTest() { GetParam().Log(); }
void SetUp() override {
ServerBuilder builder;
- builder.RegisterService(&service_);
+
+ if (!GetParam().callback_server) {
+ builder.RegisterService(&service_);
+ } else {
+ builder.RegisterService(&callback_service_);
+ }
server_ = builder.BuildAndStart();
is_server_started_ = true;
@@ -75,11 +101,13 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
test_string += "Hello world. ";
request.set_message(test_string);
-
+ grpc::string val;
if (with_binary_metadata) {
+ request.mutable_param()->set_echo_metadata(true);
char bytes[8] = {'\0', '\1', '\2', '\3',
'\4', '\5', '\6', static_cast<char>(i)};
- cli_ctx.AddMetadata("custom-bin", grpc::string(bytes, 8));
+ val = grpc::string(bytes, 8);
+ cli_ctx.AddMetadata("custom-bin", val);
}
cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
@@ -89,10 +117,18 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
bool done = false;
stub_->experimental_async()->Echo(
&cli_ctx, &request, &response,
- [&request, &response, &done, &mu, &cv](Status s) {
+ [&cli_ctx, &request, &response, &done, &mu, &cv, val,
+ with_binary_metadata](Status s) {
GPR_ASSERT(s.ok());
EXPECT_EQ(request.message(), response.message());
+ if (with_binary_metadata) {
+ EXPECT_EQ(
+ 1u, cli_ctx.GetServerTrailingMetadata().count("custom-bin"));
+ EXPECT_EQ(val, ToString(cli_ctx.GetServerTrailingMetadata()
+ .find("custom-bin")
+ ->second));
+ }
std::lock_guard<std::mutex> l(mu);
done = true;
cv.notify_one();
@@ -146,42 +182,145 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
}
}
+ void SendGenericEchoAsBidi(int num_rpcs, int reuses) {
+ const grpc::string kMethodName("/grpc.testing.EchoTestService/Echo");
+ grpc::string test_string("");
+ for (int i = 0; i < num_rpcs; i++) {
+ test_string += "Hello world. ";
+ class Client : public grpc::experimental::ClientBidiReactor<ByteBuffer,
+ ByteBuffer> {
+ public:
+ Client(ClientCallbackEnd2endTest* test, const grpc::string& method_name,
+ const grpc::string& test_str, int reuses)
+ : reuses_remaining_(reuses) {
+ activate_ = [this, test, method_name, test_str] {
+ if (reuses_remaining_ > 0) {
+ cli_ctx_.reset(new ClientContext);
+ reuses_remaining_--;
+ test->generic_stub_->experimental().PrepareBidiStreamingCall(
+ cli_ctx_.get(), method_name, this);
+ request_.set_message(test_str);
+ send_buf_ = SerializeToByteBuffer(&request_);
+ StartWrite(send_buf_.get());
+ StartRead(&recv_buf_);
+ StartCall();
+ } else {
+ std::unique_lock<std::mutex> l(mu_);
+ done_ = true;
+ cv_.notify_one();
+ }
+ };
+ activate_();
+ }
+ void OnWriteDone(bool ok) override { StartWritesDone(); }
+ void OnReadDone(bool ok) override {
+ EchoResponse response;
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buf_, &response));
+ EXPECT_EQ(request_.message(), response.message());
+ };
+ void OnDone(const Status& s) override {
+ EXPECT_TRUE(s.ok());
+ activate_();
+ }
+ void Await() {
+ std::unique_lock<std::mutex> l(mu_);
+ while (!done_) {
+ cv_.wait(l);
+ }
+ }
+
+ EchoRequest request_;
+ std::unique_ptr<ByteBuffer> send_buf_;
+ ByteBuffer recv_buf_;
+ std::unique_ptr<ClientContext> cli_ctx_;
+ int reuses_remaining_;
+ std::function<void()> activate_;
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool done_ = false;
+ } rpc{this, kMethodName, test_string, reuses};
+
+ rpc.Await();
+ }
+ }
bool is_server_started_;
std::shared_ptr<Channel> channel_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<grpc::GenericStub> generic_stub_;
TestServiceImpl service_;
+ CallbackTestServiceImpl callback_service_;
std::unique_ptr<Server> server_;
};
-TEST_F(ClientCallbackEnd2endTest, SimpleRpc) {
+TEST_P(ClientCallbackEnd2endTest, SimpleRpc) {
ResetStub();
SendRpcs(1, false);
}
-TEST_F(ClientCallbackEnd2endTest, SequentialRpcs) {
+TEST_P(ClientCallbackEnd2endTest, SequentialRpcs) {
ResetStub();
SendRpcs(10, false);
}
-TEST_F(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
+TEST_P(ClientCallbackEnd2endTest, SendClientInitialMetadata) {
+ ResetStub();
+ SimpleRequest request;
+ SimpleResponse response;
+ ClientContext cli_ctx;
+
+ cli_ctx.AddMetadata(kCheckClientInitialMetadataKey,
+ kCheckClientInitialMetadataVal);
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ stub_->experimental_async()->CheckClientInitialMetadata(
+ &cli_ctx, &request, &response, [&done, &mu, &cv](Status s) {
+ GPR_ASSERT(s.ok());
+
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+}
+
+TEST_P(ClientCallbackEnd2endTest, SimpleRpcWithBinaryMetadata) {
+ ResetStub();
+ SendRpcs(1, true);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
ResetStub();
SendRpcs(10, true);
}
-TEST_F(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
ResetStub();
SendRpcsGeneric(10, false);
}
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidi) {
+ ResetStub();
+ SendGenericEchoAsBidi(10, 1);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidiWithReactorReuse) {
+ ResetStub();
+ SendGenericEchoAsBidi(10, 10);
+}
+
#if GRPC_ALLOW_EXCEPTIONS
-TEST_F(ClientCallbackEnd2endTest, ExceptingRpc) {
+TEST_P(ClientCallbackEnd2endTest, ExceptingRpc) {
ResetStub();
SendRpcsGeneric(10, true);
}
#endif
-TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
+TEST_P(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
ResetStub();
std::vector<std::thread> threads;
threads.reserve(10);
@@ -193,7 +332,7 @@ TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
}
}
-TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) {
+TEST_P(ClientCallbackEnd2endTest, MultipleRpcs) {
ResetStub();
std::vector<std::thread> threads;
threads.reserve(10);
@@ -205,7 +344,7 @@ TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) {
}
}
-TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
+TEST_P(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -230,12 +369,167 @@ TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
}
}
+TEST_P(ClientCallbackEnd2endTest, RequestStream) {
+ ResetStub();
+ class Client : public grpc::experimental::ClientWriteReactor<EchoRequest> {
+ public:
+ explicit Client(grpc::testing::EchoTestService::Stub* stub) {
+ context_.set_initial_metadata_corked(true);
+ stub->experimental_async()->RequestStream(&context_, &response_, this);
+ StartCall();
+ request_.set_message("Hello server.");
+ StartWrite(&request_);
+ }
+ void OnWriteDone(bool ok) override {
+ writes_left_--;
+ if (writes_left_ > 1) {
+ StartWrite(&request_);
+ } else if (writes_left_ == 1) {
+ StartWriteLast(&request_, WriteOptions());
+ }
+ }
+ void OnDone(const Status& s) override {
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(response_.message(), "Hello server.Hello server.Hello server.");
+ std::unique_lock<std::mutex> l(mu_);
+ done_ = true;
+ cv_.notify_one();
+ }
+ void Await() {
+ std::unique_lock<std::mutex> l(mu_);
+ while (!done_) {
+ cv_.wait(l);
+ }
+ }
+
+ private:
+ EchoRequest request_;
+ EchoResponse response_;
+ ClientContext context_;
+ int writes_left_{3};
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool done_ = false;
+ } test{stub_.get()};
+
+ test.Await();
+}
+
+TEST_P(ClientCallbackEnd2endTest, ResponseStream) {
+ ResetStub();
+ class Client : public grpc::experimental::ClientReadReactor<EchoResponse> {
+ public:
+ explicit Client(grpc::testing::EchoTestService::Stub* stub) {
+ request_.set_message("Hello client ");
+ stub->experimental_async()->ResponseStream(&context_, &request_, this);
+ StartCall();
+ StartRead(&response_);
+ }
+ void OnReadDone(bool ok) override {
+ if (!ok) {
+ EXPECT_EQ(reads_complete_, kServerDefaultResponseStreamsToSend);
+ } else {
+ EXPECT_LE(reads_complete_, kServerDefaultResponseStreamsToSend);
+ EXPECT_EQ(response_.message(),
+ request_.message() + grpc::to_string(reads_complete_));
+ reads_complete_++;
+ StartRead(&response_);
+ }
+ }
+ void OnDone(const Status& s) override {
+ EXPECT_TRUE(s.ok());
+ std::unique_lock<std::mutex> l(mu_);
+ done_ = true;
+ cv_.notify_one();
+ }
+ void Await() {
+ std::unique_lock<std::mutex> l(mu_);
+ while (!done_) {
+ cv_.wait(l);
+ }
+ }
+
+ private:
+ EchoRequest request_;
+ EchoResponse response_;
+ ClientContext context_;
+ int reads_complete_{0};
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool done_ = false;
+ } test{stub_.get()};
+
+ test.Await();
+}
+
+TEST_P(ClientCallbackEnd2endTest, BidiStream) {
+ ResetStub();
+ class Client : public grpc::experimental::ClientBidiReactor<EchoRequest,
+ EchoResponse> {
+ public:
+ explicit Client(grpc::testing::EchoTestService::Stub* stub) {
+ request_.set_message("Hello fren ");
+ stub->experimental_async()->BidiStream(&context_, this);
+ StartCall();
+ StartRead(&response_);
+ StartWrite(&request_);
+ }
+ void OnReadDone(bool ok) override {
+ if (!ok) {
+ EXPECT_EQ(reads_complete_, kServerDefaultResponseStreamsToSend);
+ } else {
+ EXPECT_LE(reads_complete_, kServerDefaultResponseStreamsToSend);
+ EXPECT_EQ(response_.message(), request_.message());
+ reads_complete_++;
+ StartRead(&response_);
+ }
+ }
+ void OnWriteDone(bool ok) override {
+ EXPECT_TRUE(ok);
+ if (++writes_complete_ == kServerDefaultResponseStreamsToSend) {
+ StartWritesDone();
+ } else {
+ StartWrite(&request_);
+ }
+ }
+ void OnDone(const Status& s) override {
+ EXPECT_TRUE(s.ok());
+ std::unique_lock<std::mutex> l(mu_);
+ done_ = true;
+ cv_.notify_one();
+ }
+ void Await() {
+ std::unique_lock<std::mutex> l(mu_);
+ while (!done_) {
+ cv_.wait(l);
+ }
+ }
+
+ private:
+ EchoRequest request_;
+ EchoResponse response_;
+ ClientContext context_;
+ int reads_complete_{0};
+ int writes_complete_{0};
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool done_ = false;
+ } test{stub_.get()};
+
+ test.Await();
+}
+
+TestScenario scenarios[] = {TestScenario{false}, TestScenario{true}};
+
+INSTANTIATE_TEST_CASE_P(ClientCallbackEnd2endTest, ClientCallbackEnd2endTest,
+ ::testing::ValuesIn(scenarios));
+
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index 2a06f44c60..992f3c488f 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -135,7 +135,7 @@ int main(int argc, char** argv) {
g_root = ".";
}
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
// Order seems to matter on these tests: run three times to eliminate that
for (int i = 0; i < 3; i++) {
diff --git a/test/cpp/end2end/client_interceptors_end2end_test.cc b/test/cpp/end2end/client_interceptors_end2end_test.cc
new file mode 100644
index 0000000000..968b5d49d1
--- /dev/null
+++ b/test/cpp/end2end/client_interceptors_end2end_test.cc
@@ -0,0 +1,651 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <memory>
+#include <vector>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+/* Hijacks Echo RPC and fills in the expected values */
+class HijackingInterceptor : public experimental::Interceptor {
+ public:
+ HijackingInterceptor(experimental::ClientRpcInfo* info) {
+ info_ = info;
+ // Make sure it is the right method
+ EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+ EXPECT_EQ(info->type(), experimental::ClientRpcInfo::Type::UNARY);
+ }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ bool hijack = false;
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ hijack = true;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_EQ(req.message(), "Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ // Check that we got the hijacked message, and re-insert the expected
+ // message
+ EXPECT_EQ(resp->message(), "Hello1");
+ resp->set_message("Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here at the moment
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) {
+ // Insert a different message than expected
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ resp->set_message("Hello1");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ // insert the metadata that we want
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ map->insert(std::make_pair("testkey", "testvalue"));
+ auto* status = methods->GetRecvStatus();
+ *status = Status(StatusCode::OK, "");
+ }
+ if (hijack) {
+ methods->Hijack();
+ } else {
+ methods->Proceed();
+ }
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+};
+
+class HijackingInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new HijackingInterceptor(info);
+ }
+};
+
+class HijackingInterceptorMakesAnotherCall : public experimental::Interceptor {
+ public:
+ HijackingInterceptorMakesAnotherCall(experimental::ClientRpcInfo* info) {
+ info_ = info;
+ // Make sure it is the right method
+ EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+ }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ // Make a copy of the map
+ metadata_map_ = *map;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_EQ(req.message(), "Hello");
+ req_ = req;
+ stub_ = grpc::testing::EchoTestService::NewStub(
+ methods->GetInterceptedChannel());
+ ctx_.AddMetadata(metadata_map_.begin()->first,
+ metadata_map_.begin()->second);
+ stub_->experimental_async()->Echo(&ctx_, &req_, &resp_,
+ [this, methods](Status s) {
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp_.message(), "Hello");
+ methods->Hijack();
+ });
+ // There isn't going to be any other interesting operation in this batch,
+ // so it is fine to return
+ return;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ // Check that we got the hijacked message, and re-insert the expected
+ // message
+ EXPECT_EQ(resp->message(), "Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here at the moment
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) {
+ // Insert a different message than expected
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ resp->set_message(resp_.message());
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ // insert the metadata that we want
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ map->insert(std::make_pair("testkey", "testvalue"));
+ auto* status = methods->GetRecvStatus();
+ *status = Status(StatusCode::OK, "");
+ }
+
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+ std::multimap<grpc::string, grpc::string> metadata_map_;
+ ClientContext ctx_;
+ EchoRequest req_;
+ EchoResponse resp_;
+ std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+};
+
+class HijackingInterceptorMakesAnotherCallFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new HijackingInterceptorMakesAnotherCall(info);
+ }
+};
+
+class LoggingInterceptor : public experimental::Interceptor {
+ public:
+ LoggingInterceptor(experimental::ClientRpcInfo* info) { info_ = info; }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_TRUE(req.message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ EXPECT_TRUE(resp->message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+};
+
+class LoggingInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new LoggingInterceptor(info);
+ }
+};
+
+class ClientInterceptorsEnd2endTest : public ::testing::Test {
+ protected:
+ ClientInterceptorsEnd2endTest() {
+ int port = grpc_pick_unused_port_or_die();
+
+ ServerBuilder builder;
+ server_address_ = "localhost:" + std::to_string(port);
+ builder.AddListeningPort(server_address_, InsecureServerCredentials());
+ builder.RegisterService(&service_);
+ server_ = builder.BuildAndStart();
+ }
+
+ ~ClientInterceptorsEnd2endTest() { server_->Shutdown(); }
+
+ std::string server_address_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLoggingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorHijackingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy interceptors before hijacking interceptor
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ creators.push_back(std::unique_ptr<HijackingInterceptorFactory>(
+ new HijackingInterceptorFactory()));
+ // Add 20 dummy interceptors after hijacking interceptor
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+
+ MakeCall(channel);
+ // Make sure only 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLogThenHijackTest) {
+ ChannelArguments args;
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ creators.push_back(std::unique_ptr<HijackingInterceptorFactory>(
+ new HijackingInterceptorFactory()));
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+
+ MakeCall(channel);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest,
+ ClientInterceptorHijackingMakesAnotherCallTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 5 dummy interceptors before hijacking interceptor
+ creators.reserve(5);
+ for (auto i = 0; i < 5; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ creators.push_back(
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>(
+ new HijackingInterceptorMakesAnotherCallFactory()));
+ // Add 7 dummy interceptors after hijacking interceptor
+ for (auto i = 0; i < 7; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = server_->experimental().InProcessChannelWithInterceptors(
+ args, std::move(creators));
+
+ MakeCall(channel);
+ // Make sure all interceptors were run once, since the hijacking interceptor
+ // makes an RPC on the intercepted channel
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 12);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest,
+ ClientInterceptorLoggingTestWithCallback) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = server_->experimental().InProcessChannelWithInterceptors(
+ args, std::move(creators));
+ MakeCallbackCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ClientInterceptorsStreamingEnd2endTest : public ::testing::Test {
+ protected:
+ ClientInterceptorsStreamingEnd2endTest() {
+ int port = grpc_pick_unused_port_or_die();
+
+ ServerBuilder builder;
+ server_address_ = "localhost:" + std::to_string(port);
+ builder.AddListeningPort(server_address_, InsecureServerCredentials());
+ builder.RegisterService(&service_);
+ server_ = builder.BuildAndStart();
+ }
+
+ ~ClientInterceptorsStreamingEnd2endTest() { server_->Shutdown(); }
+
+ std::string server_address_;
+ EchoTestServiceStreamingImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, ClientStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeClientStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, ServerStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeServerStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, BidiStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeBidiStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ClientGlobalInterceptorEnd2endTest : public ::testing::Test {
+ protected:
+ ClientGlobalInterceptorEnd2endTest() {
+ int port = grpc_pick_unused_port_or_die();
+
+ ServerBuilder builder;
+ server_address_ = "localhost:" + std::to_string(port);
+ builder.AddListeningPort(server_address_, InsecureServerCredentials());
+ builder.RegisterService(&service_);
+ server_ = builder.BuildAndStart();
+ }
+
+ ~ClientGlobalInterceptorEnd2endTest() { server_->Shutdown(); }
+
+ std::string server_address_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientGlobalInterceptorEnd2endTest, DummyGlobalInterceptor) {
+ // We should ideally be registering a global interceptor only once per
+ // process, but for the purposes of testing, it should be fine to modify the
+ // registered global interceptor when there are no ongoing gRPC operations
+ DummyInterceptorFactory global_factory;
+ experimental::RegisterGlobalClientInterceptorFactory(&global_factory);
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy interceptors
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run with the global interceptor
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 21);
+ // Reset the global interceptor. This is again 'safe' because there are no
+ // other ongoing gRPC operations
+ experimental::RegisterGlobalClientInterceptorFactory(nullptr);
+}
+
+TEST_F(ClientGlobalInterceptorEnd2endTest, LoggingGlobalInterceptor) {
+ // We should ideally be registering a global interceptor only once per
+ // process, but for the purposes of testing, it should be fine to modify the
+ // registered global interceptor when there are no ongoing gRPC operations
+ LoggingInterceptorFactory global_factory;
+ experimental::RegisterGlobalClientInterceptorFactory(&global_factory);
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy interceptors
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+ // Reset the global interceptor. This is again 'safe' because there are no
+ // other ongoing gRPC operations
+ experimental::RegisterGlobalClientInterceptorFactory(nullptr);
+}
+
+TEST_F(ClientGlobalInterceptorEnd2endTest, HijackingGlobalInterceptor) {
+ // We should ideally be registering a global interceptor only once per
+ // process, but for the purposes of testing, it should be fine to modify the
+ // registered global interceptor when there are no ongoing gRPC operations
+ HijackingInterceptorFactory global_factory;
+ experimental::RegisterGlobalClientInterceptorFactory(&global_factory);
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy interceptors
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+ // Reset the global interceptor. This is again 'safe' because there are no
+ // other ongoing gRPC operations
+ experimental::RegisterGlobalClientInterceptorFactory(nullptr);
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc
index 77c25c1416..1dfa91a76c 100644
--- a/test/cpp/end2end/client_lb_end2end_test.cc
+++ b/test/cpp/end2end/client_lb_end2end_test.cc
@@ -42,6 +42,9 @@
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+#include "src/cpp/client/secure_credentials.h"
+#include "src/cpp/server/secure_server_credentials.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
@@ -113,7 +116,10 @@ class MyTestServiceImpl : public TestServiceImpl {
class ClientLbEnd2endTest : public ::testing::Test {
protected:
ClientLbEnd2endTest()
- : server_host_("localhost"), kRequestMessage_("Live long and prosper.") {
+ : server_host_("localhost"),
+ kRequestMessage_("Live long and prosper."),
+ creds_(new SecureChannelCredentials(
+ grpc_fake_transport_security_credentials_create())) {
// Make the backup poller poll very frequently in order to pick up
// updates from all the subchannels's FDs.
gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1");
@@ -146,7 +152,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
void StartServers(size_t num_servers,
std::vector<int> ports = std::vector<int>()) {
- CreateServers(num_servers, ports);
+ CreateServers(num_servers, std::move(ports));
for (size_t i = 0; i < num_servers; ++i) {
StartServer(i);
}
@@ -188,6 +194,11 @@ class ClientLbEnd2endTest : public ::testing::Test {
grpc_channel_args_destroy(fake_results);
}
+ void SetFailureOnReresolution() {
+ grpc_core::ExecCtx exec_ctx;
+ response_generator_->SetFailureOnReresolution();
+ }
+
std::vector<int> GetServersPorts() {
std::vector<int> ports;
for (const auto& server : servers_) ports.push_back(server->port_);
@@ -207,19 +218,20 @@ class ClientLbEnd2endTest : public ::testing::Test {
} // else, default to pick first
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_.get());
- return CreateCustomChannel("fake:///", InsecureChannelCredentials(), args);
+ return CreateCustomChannel("fake:///", creds_, args);
}
bool SendRpc(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
EchoResponse* response = nullptr, int timeout_ms = 1000,
- Status* result = nullptr) {
+ Status* result = nullptr, bool wait_for_ready = false) {
const bool local_response = (response == nullptr);
if (local_response) response = new EchoResponse;
EchoRequest request;
request.set_message(kRequestMessage_);
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
+ if (wait_for_ready) context.set_wait_for_ready(true);
Status status = stub->Echo(&context, request, response);
if (result != nullptr) *result = status;
if (local_response) delete response;
@@ -228,10 +240,11 @@ class ClientLbEnd2endTest : public ::testing::Test {
void CheckRpcSendOk(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
- const grpc_core::DebugLocation& location) {
+ const grpc_core::DebugLocation& location, bool wait_for_ready = false) {
EchoResponse response;
Status status;
- const bool success = SendRpc(stub, &response, 2000, &status);
+ const bool success =
+ SendRpc(stub, &response, 2000, &status, wait_for_ready);
ASSERT_TRUE(success) << "From " << location.file() << ":" << location.line()
<< "\n"
<< "Error: " << status.error_message() << " "
@@ -253,6 +266,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
MyTestServiceImpl service_;
std::unique_ptr<std::thread> thread_;
bool server_ready_ = false;
+ bool started_ = false;
explicit ServerData(int port = 0) {
port_ = port > 0 ? port : grpc_pick_unused_port_or_die();
@@ -260,6 +274,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
void Start(const grpc::string& server_host) {
gpr_log(GPR_INFO, "starting server on port %d", port_);
+ started_ = true;
std::mutex mu;
std::unique_lock<std::mutex> lock(mu);
std::condition_variable cond;
@@ -275,8 +290,9 @@ class ClientLbEnd2endTest : public ::testing::Test {
std::ostringstream server_address;
server_address << server_host << ":" << port_;
ServerBuilder builder;
- builder.AddListeningPort(server_address.str(),
- InsecureServerCredentials());
+ std::shared_ptr<ServerCredentials> creds(new SecureServerCredentials(
+ grpc_fake_transport_security_server_credentials_create()));
+ builder.AddListeningPort(server_address.str(), std::move(creds));
builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
std::lock_guard<std::mutex> lock(*mu);
@@ -284,9 +300,11 @@ class ClientLbEnd2endTest : public ::testing::Test {
cond->notify_one();
}
- void Shutdown(bool join = true) {
+ void Shutdown() {
+ if (!started_) return;
server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
- if (join) thread_->join();
+ thread_->join();
+ started_ = false;
}
void SetServingStatus(const grpc::string& service, bool serving) {
@@ -306,7 +324,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
if (ignore_failure) {
SendRpc(stub);
} else {
- CheckRpcSendOk(stub, location);
+ CheckRpcSendOk(stub, location, true);
}
} while (servers_[server_idx]->service_.request_count() == 0);
ResetCounters();
@@ -365,6 +383,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
const grpc::string kRequestMessage_;
+ std::shared_ptr<ChannelCredentials> creds_;
};
TEST_F(ClientLbEnd2endTest, PickFirst) {
@@ -409,6 +428,30 @@ TEST_F(ClientLbEnd2endTest, PickFirstProcessPending) {
CheckRpcSendOk(second_stub, DEBUG_LOCATION);
}
+TEST_F(ClientLbEnd2endTest, PickFirstSelectsReadyAtStartup) {
+ ChannelArguments args;
+ constexpr int kInitialBackOffMs = 5000;
+ args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
+ // Create 2 servers, but start only the second one.
+ std::vector<int> ports = {grpc_pick_unused_port_or_die(),
+ grpc_pick_unused_port_or_die()};
+ CreateServers(2, ports);
+ StartServer(1);
+ auto channel1 = BuildChannel("pick_first", args);
+ auto stub1 = BuildStub(channel1);
+ SetNextResolution(ports);
+ // Wait for second server to be ready.
+ WaitForServer(stub1, 1, DEBUG_LOCATION);
+ // Create a second channel with the same addresses. Its PF instance
+ // should immediately pick the second subchannel, since it's already
+ // in READY state.
+ auto channel2 = BuildChannel("pick_first", args);
+ SetNextResolution(ports);
+ // Check that the channel reports READY without waiting for the
+ // initial backoff.
+ EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1 /* timeout_seconds */));
+}
+
TEST_F(ClientLbEnd2endTest, PickFirstBackOffInitialReconnect) {
ChannelArguments args;
constexpr int kInitialBackOffMs = 100;
@@ -494,6 +537,51 @@ TEST_F(ClientLbEnd2endTest, PickFirstResetConnectionBackoff) {
EXPECT_LT(waited_ms, kInitialBackOffMs);
}
+TEST_F(ClientLbEnd2endTest,
+ PickFirstResetConnectionBackoffNextAttemptStartsImmediately) {
+ ChannelArguments args;
+ constexpr int kInitialBackOffMs = 1000;
+ args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
+ const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
+ auto channel = BuildChannel("pick_first", args);
+ auto stub = BuildStub(channel);
+ SetNextResolution(ports);
+ // Wait for connect, which should fail ~immediately, because the server
+ // is not up.
+ gpr_log(GPR_INFO, "=== INITIAL CONNECTION ATTEMPT");
+ EXPECT_FALSE(
+ channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10)));
+ // Reset connection backoff.
+ // Note that the time at which the third attempt will be started is
+ // actually computed at this point, so we record the start time here.
+ gpr_log(GPR_INFO, "=== RESETTING BACKOFF");
+ const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC);
+ experimental::ChannelResetConnectionBackoff(channel.get());
+ // Trigger a second connection attempt. This should also fail
+ // ~immediately, but the retry should be scheduled for
+ // kInitialBackOffMs instead of applying the multiplier.
+ gpr_log(GPR_INFO, "=== POLLING FOR SECOND CONNECTION ATTEMPT");
+ EXPECT_FALSE(
+ channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10)));
+ // Bring up a server on the chosen port.
+ gpr_log(GPR_INFO, "=== STARTING BACKEND");
+ StartServers(1, ports);
+ // Wait for connect. Should happen within kInitialBackOffMs.
+ // Give an extra 100ms to account for the time spent in the second and
+ // third connection attempts themselves (since what we really want to
+ // measure is the time between the two). As long as this is less than
+ // the 1.6x increase we would see if the backoff state was not reset
+ // properly, the test is still proving that the backoff was reset.
+ constexpr int kWaitMs = kInitialBackOffMs + 100;
+ gpr_log(GPR_INFO, "=== POLLING FOR THIRD CONNECTION ATTEMPT");
+ EXPECT_TRUE(channel->WaitForConnected(
+ grpc_timeout_milliseconds_to_deadline(kWaitMs)));
+ const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC);
+ const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0));
+ gpr_log(GPR_DEBUG, "Waited %" PRId64 " milliseconds", waited_ms);
+ EXPECT_LT(waited_ms, kWaitMs);
+}
+
TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
@@ -518,7 +606,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
do {
channel_state = channel->GetState(true /* try to connect */);
} while (channel_state == GRPC_CHANNEL_READY);
- GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
+ ASSERT_NE(channel_state, GRPC_CHANNEL_READY);
servers_[0]->service_.ResetCounters();
// Next update introduces servers_[1], making the channel recover.
@@ -720,6 +808,23 @@ TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
EXPECT_EQ("pick_first", channel_2->GetLoadBalancingPolicyName());
}
+TEST_F(ClientLbEnd2endTest, PickFirstIdleOnDisconnect) {
+ // Start server, send RPC, and make sure channel is READY.
+ const int kNumServers = 1;
+ StartServers(kNumServers);
+ auto channel = BuildChannel(""); // pick_first is the default.
+ auto stub = BuildStub(channel);
+ SetNextResolution(GetServersPorts());
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+ EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
+ // Stop server. Channel should go into state IDLE.
+ SetFailureOnReresolution();
+ servers_[0]->Shutdown();
+ EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
+ EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_IDLE);
+ servers_.clear();
+}
+
TEST_F(ClientLbEnd2endTest, RoundRobin) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
@@ -835,7 +940,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
do {
channel_state = channel->GetState(true /* try to connect */);
} while (channel_state == GRPC_CHANNEL_READY);
- GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
+ ASSERT_NE(channel_state, GRPC_CHANNEL_READY);
servers_[0]->service_.ResetCounters();
// Next update introduces servers_[1], making the channel recover.
@@ -844,7 +949,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
SetNextResolution(ports);
WaitForServer(stub, 1, DEBUG_LOCATION);
channel_state = channel->GetState(false /* try to connect */);
- GPR_ASSERT(channel_state == GRPC_CHANNEL_READY);
+ ASSERT_EQ(channel_state, GRPC_CHANNEL_READY);
// Check LB policy name for the channel.
EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
@@ -869,7 +974,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) {
servers_[0]->service_.ResetCounters();
// Shutdown one of the servers to be sent in the update.
- servers_[1]->Shutdown(false);
+ servers_[1]->Shutdown();
ports.emplace_back(servers_[1]->port_);
ports.emplace_back(servers_[2]->port_);
SetNextResolution(ports);
@@ -928,7 +1033,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
// Kill all servers
gpr_log(GPR_INFO, "****** ABOUT TO KILL SERVERS *******");
for (size_t i = 0; i < servers_.size(); ++i) {
- servers_[i]->Shutdown(true);
+ servers_[i]->Shutdown();
}
gpr_log(GPR_INFO, "****** SERVERS KILLED *******");
gpr_log(GPR_INFO, "****** SENDING DOOMED REQUESTS *******");
@@ -954,7 +1059,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
if (SendRpc(stub)) break;
now = gpr_now(GPR_CLOCK_MONOTONIC);
}
- GPR_ASSERT(gpr_time_cmp(deadline, now) > 0);
+ ASSERT_GT(gpr_time_cmp(deadline, now), 0);
}
TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
@@ -976,7 +1081,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
}
const auto pre_death = servers_[0]->service_.request_count();
// Kill the first server.
- servers_[0]->Shutdown(true);
+ servers_[0]->Shutdown();
// Client request still succeed. May need retrying if RR had returned a pick
// before noticing the change in the server's connectivity.
while (!SendRpc(stub)) {
@@ -1123,7 +1228,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingInhibitPerChannel) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
const auto result = RUN_ALL_TESTS();
return result;
}
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index fc07681535..05cd4330c6 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -40,6 +40,7 @@
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
#include "test/cpp/end2end/test_service_impl.h"
#include "test/cpp/util/string_ref_helper.h"
#include "test/cpp/util/test_credentials_provider.h"
@@ -179,7 +180,7 @@ class Proxy : public ::grpc::testing::EchoTestService::Service {
}
private:
- std::unique_ptr< ::grpc::testing::EchoTestService::Stub> stub_;
+ std::unique_ptr<::grpc::testing::EchoTestService::Stub> stub_;
};
class TestServiceImplDupPkg
@@ -194,19 +195,29 @@ class TestServiceImplDupPkg
class TestScenario {
public:
- TestScenario(bool proxy, bool inproc_stub, const grpc::string& creds_type)
- : use_proxy(proxy), inproc(inproc_stub), credentials_type(creds_type) {}
+ TestScenario(bool interceptors, bool proxy, bool inproc_stub,
+ const grpc::string& creds_type, bool use_callback_server)
+ : use_interceptors(interceptors),
+ use_proxy(proxy),
+ inproc(inproc_stub),
+ credentials_type(creds_type),
+ callback_server(use_callback_server) {}
void Log() const;
+ bool use_interceptors;
bool use_proxy;
bool inproc;
const grpc::string credentials_type;
+ bool callback_server;
};
static std::ostream& operator<<(std::ostream& out,
const TestScenario& scenario) {
- return out << "TestScenario{use_proxy="
- << (scenario.use_proxy ? "true" : "false")
+ return out << "TestScenario{use_interceptors="
+ << (scenario.use_interceptors ? "true" : "false")
+ << ", use_proxy=" << (scenario.use_proxy ? "true" : "false")
<< ", inproc=" << (scenario.inproc ? "true" : "false")
+ << ", server_type="
+ << (scenario.callback_server ? "callback" : "sync")
<< ", credentials='" << scenario.credentials_type << "'}";
}
@@ -260,8 +271,24 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
if (GetParam().credentials_type != kInsecureCredentialsType) {
server_creds->SetAuthMetadataProcessor(processor);
}
+ if (GetParam().use_interceptors) {
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy server interceptors
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ }
builder.AddListeningPort(server_address_.str(), server_creds);
- builder.RegisterService(&service_);
+ if (!GetParam().callback_server) {
+ builder.RegisterService(&service_);
+ } else {
+ builder.RegisterService(&callback_service_);
+ }
builder.RegisterService("foo.test.youtube.com", &special_service_);
builder.RegisterService(&dup_pkg_service_);
@@ -292,10 +319,21 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
if (!GetParam().inproc) {
- channel_ =
- CreateCustomChannel(server_address_.str(), channel_creds, args);
+ if (!GetParam().use_interceptors) {
+ channel_ =
+ CreateCustomChannel(server_address_.str(), channel_creds, args);
+ } else {
+ channel_ = CreateCustomChannelWithInterceptors(
+ server_address_.str(), channel_creds, args,
+ CreateDummyClientInterceptors());
+ }
} else {
- channel_ = server_->InProcessChannel(args);
+ if (!GetParam().use_interceptors) {
+ channel_ = server_->InProcessChannel(args);
+ } else {
+ channel_ = server_->experimental().InProcessChannelWithInterceptors(
+ args, CreateDummyClientInterceptors());
+ }
}
}
@@ -320,6 +358,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
}
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+ DummyInterceptor::Reset();
}
bool is_server_started_;
@@ -331,6 +370,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
std::ostringstream server_address_;
const int kMaxMessageSize_;
TestServiceImpl service_;
+ CallbackTestServiceImpl callback_service_;
TestServiceImpl special_service_;
TestServiceImplDupPkg dup_pkg_service_;
grpc::string user_agent_prefix_;
@@ -376,6 +416,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestRequestStreamServerCancel(
ServerTryCancelRequestPhase server_try_cancel, int num_msgs_to_send) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -432,6 +473,10 @@ class End2endServerTryCancelTest : public End2endTest {
EXPECT_FALSE(s.ok());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Helper for testing server-streaming RPCs which are cancelled on the server.
@@ -449,6 +494,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestResponseStreamServerCancel(
ServerTryCancelRequestPhase server_try_cancel) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -508,7 +554,10 @@ class End2endServerTryCancelTest : public End2endTest {
}
EXPECT_FALSE(s.ok());
- EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Helper for testing bidirectional-streaming RPCs which are cancelled on the
@@ -526,6 +575,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestBidiStreamServerCancel(ServerTryCancelRequestPhase server_try_cancel,
int num_messages) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -592,6 +642,10 @@ class End2endServerTryCancelTest : public End2endTest {
EXPECT_FALSE(s.ok());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
};
@@ -971,7 +1025,8 @@ TEST_P(End2endTest, DiffPackageServices) {
EXPECT_TRUE(s.ok());
}
-void CancelRpc(ClientContext* context, int delay_us, TestServiceImpl* service) {
+template <class ServiceType>
+void CancelRpc(ClientContext* context, int delay_us, ServiceType* service) {
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_micros(delay_us, GPR_TIMESPAN)));
while (!service->signal_client()) {
@@ -989,6 +1044,9 @@ TEST_P(End2endTest, CancelRpcBeforeStart) {
Status s = stub_->Echo(&context, request, &response);
EXPECT_EQ("", response.message());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels request stream after sending two messages
@@ -1009,6 +1067,9 @@ TEST_P(End2endTest, ClientCancelsRequestStream) {
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
EXPECT_EQ(response.message(), "");
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels server stream after sending some messages
@@ -1041,6 +1102,9 @@ TEST_P(End2endTest, ClientCancelsResponseStream) {
// The final status could be either of CANCELLED or OK depending on
// who won the race.
EXPECT_GE(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels bidi stream after sending some messages
@@ -1074,6 +1138,9 @@ TEST_P(End2endTest, ClientCancelsBidi) {
Status s = stream->Finish();
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
TEST_P(End2endTest, RpcMaxMessageSize) {
@@ -1389,7 +1456,24 @@ TEST_P(ProxyEnd2endTest, ClientCancelsRpc) {
request.mutable_param()->set_client_cancel_after_us(kCancelDelayUs);
ClientContext context;
- std::thread cancel_thread(CancelRpc, &context, kCancelDelayUs, &service_);
+ std::thread cancel_thread;
+ if (!GetParam().callback_server) {
+ cancel_thread = std::thread(
+ [&context, this](int delay) { CancelRpc(&context, delay, &service_); },
+ kCancelDelayUs);
+ // Note: the unusual pattern above (and below) is caused by a conflict
+ // between two sets of compiler expectations. clang allows const to be
+ // captured without mention, so there is no need to capture kCancelDelayUs
+ // (and indeed clang-tidy complains if you do so). OTOH, a Windows compiler
+ // in our tests requires an explicit capture even for const. We square this
+ // circle by passing the const value in as an argument to the lambda.
+ } else {
+ cancel_thread = std::thread(
+ [&context, this](int delay) {
+ CancelRpc(&context, delay, &callback_service_);
+ },
+ kCancelDelayUs);
+ }
Status s = stub_->Echo(&context, request, &response);
cancel_thread.join();
EXPECT_EQ(StatusCode::CANCELLED, s.error_code());
@@ -1781,10 +1865,12 @@ TEST_P(ResourceQuotaEnd2endTest, SimpleRequest) {
EXPECT_TRUE(s.ok());
}
+// TODO(vjpai): refactor arguments into a struct if it makes sense
std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
bool test_insecure,
bool test_secure,
- bool test_inproc) {
+ bool test_inproc,
+ bool test_callback_server) {
std::vector<TestScenario> scenarios;
std::vector<grpc::string> credentials_types;
if (test_secure) {
@@ -1800,38 +1886,48 @@ std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
if (test_insecure && insec_ok()) {
credentials_types.push_back(kInsecureCredentialsType);
}
+
+ // For now test callback server only with inproc
GPR_ASSERT(!credentials_types.empty());
for (const auto& cred : credentials_types) {
- scenarios.emplace_back(false, false, cred);
+ scenarios.emplace_back(false, false, false, cred, false);
+ scenarios.emplace_back(true, false, false, cred, false);
if (use_proxy) {
- scenarios.emplace_back(true, false, cred);
+ scenarios.emplace_back(false, true, false, cred, false);
+ scenarios.emplace_back(true, true, false, cred, false);
}
}
if (test_inproc && insec_ok()) {
- scenarios.emplace_back(false, true, kInsecureCredentialsType);
+ scenarios.emplace_back(false, false, true, kInsecureCredentialsType, false);
+ scenarios.emplace_back(true, false, true, kInsecureCredentialsType, false);
+ if (test_callback_server) {
+ scenarios.emplace_back(false, false, true, kInsecureCredentialsType,
+ true);
+ scenarios.emplace_back(true, false, true, kInsecureCredentialsType, true);
+ }
}
return scenarios;
}
-INSTANTIATE_TEST_CASE_P(End2end, End2endTest,
- ::testing::ValuesIn(CreateTestScenarios(false, true,
- true, true)));
+INSTANTIATE_TEST_CASE_P(
+ End2end, End2endTest,
+ ::testing::ValuesIn(CreateTestScenarios(false, true, true, true, true)));
-INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest,
- ::testing::ValuesIn(CreateTestScenarios(false, true,
- true, true)));
+INSTANTIATE_TEST_CASE_P(
+ End2endServerTryCancel, End2endServerTryCancelTest,
+ ::testing::ValuesIn(CreateTestScenarios(false, true, true, true, true)));
-INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest,
- ::testing::ValuesIn(CreateTestScenarios(true, true,
- true, true)));
+INSTANTIATE_TEST_CASE_P(
+ ProxyEnd2end, ProxyEnd2endTest,
+ ::testing::ValuesIn(CreateTestScenarios(true, true, true, true, false)));
-INSTANTIATE_TEST_CASE_P(SecureEnd2end, SecureEnd2endTest,
- ::testing::ValuesIn(CreateTestScenarios(false, false,
- true, false)));
+INSTANTIATE_TEST_CASE_P(
+ SecureEnd2end, SecureEnd2endTest,
+ ::testing::ValuesIn(CreateTestScenarios(false, false, true, false, true)));
-INSTANTIATE_TEST_CASE_P(ResourceQuotaEnd2end, ResourceQuotaEnd2endTest,
- ::testing::ValuesIn(CreateTestScenarios(false, true,
- true, true)));
+INSTANTIATE_TEST_CASE_P(
+ ResourceQuotaEnd2end, ResourceQuotaEnd2endTest,
+ ::testing::ValuesIn(CreateTestScenarios(false, true, true, true, false)));
} // namespace
} // namespace testing
@@ -1839,7 +1935,7 @@ INSTANTIATE_TEST_CASE_P(ResourceQuotaEnd2end, ResourceQuotaEnd2endTest,
int main(int argc, char** argv) {
gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200");
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/exception_test.cc b/test/cpp/end2end/exception_test.cc
index 5343997663..0d2c00263b 100644
--- a/test/cpp/end2end/exception_test.cc
+++ b/test/cpp/end2end/exception_test.cc
@@ -117,7 +117,7 @@ TEST_F(ExceptionTest, RequestStream) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
index 88f8f380c3..ad67402e3d 100644
--- a/test/cpp/end2end/filter_end2end_test.cc
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -331,7 +331,7 @@ void RegisterFilter() {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
grpc::testing::RegisterFilter();
return RUN_ALL_TESTS();
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 88a1227ca2..015862bfe8 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -333,7 +333,7 @@ TEST_F(GenericEnd2endTest, Deadline) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc
index b69b861fcf..9c4cd05061 100644
--- a/test/cpp/end2end/grpclb_end2end_test.cc
+++ b/test/cpp/end2end/grpclb_end2end_test.cc
@@ -539,22 +539,25 @@ class GrpclbEnd2endTest : public ::testing::Test {
balancers_.at(i)->add_response(response, delay_ms);
}
- Status SendRpc(EchoResponse* response = nullptr, int timeout_ms = 1000) {
+ Status SendRpc(EchoResponse* response = nullptr, int timeout_ms = 1000,
+ bool wait_for_ready = false) {
const bool local_response = (response == nullptr);
if (local_response) response = new EchoResponse;
EchoRequest request;
request.set_message(kRequestMessage_);
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
+ if (wait_for_ready) context.set_wait_for_ready(true);
Status status = stub_->Echo(&context, request, response);
if (local_response) delete response;
return status;
}
- void CheckRpcSendOk(const size_t times = 1, const int timeout_ms = 1000) {
+ void CheckRpcSendOk(const size_t times = 1, const int timeout_ms = 1000,
+ bool wait_for_ready = false) {
for (size_t i = 0; i < times; ++i) {
EchoResponse response;
- const Status status = SendRpc(&response, timeout_ms);
+ const Status status = SendRpc(&response, timeout_ms, wait_for_ready);
EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
<< " message=" << status.error_message();
EXPECT_EQ(response.message(), kRequestMessage_);
@@ -715,10 +718,9 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) {
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
kServerlistDelayMs);
-
const auto t0 = system_clock::now();
// Client will block: LB will initially send empty serverlist.
- CheckRpcSendOk(1, kCallDeadlineMs);
+ CheckRpcSendOk(1, kCallDeadlineMs, true /* wait_for_ready */);
const auto ellapsed_ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
system_clock::now() - t0);
@@ -1366,7 +1368,7 @@ TEST_F(SingleBalancerTest, DropAllFirst) {
{}, {{"rate_limiting", num_of_drop_by_rate_limiting_addresses},
{"load_balancing", num_of_drop_by_load_balancing_addresses}}),
0);
- const Status status = SendRpc();
+ const Status status = SendRpc(nullptr, 1000, true);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
}
@@ -1391,7 +1393,7 @@ TEST_F(SingleBalancerTest, DropAll) {
// fail.
Status status;
do {
- status = SendRpc();
+ status = SendRpc(nullptr, 1000, true);
} while (status.ok());
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
@@ -1516,7 +1518,7 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) {
int main(int argc, char** argv) {
grpc_init();
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
const auto result = RUN_ALL_TESTS();
grpc_shutdown();
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
index fca65dfc13..b96ff53a3e 100644
--- a/test/cpp/end2end/health_service_end2end_test.cc
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -37,6 +37,7 @@
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_health_check_service_impl.h"
#include "test/cpp/end2end/test_service_impl.h"
#include <gtest/gtest.h>
@@ -49,62 +50,6 @@ namespace grpc {
namespace testing {
namespace {
-// A sample sync implementation of the health checking service. This does the
-// same thing as the default one.
-class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service {
- public:
- Status Check(ServerContext* context, const HealthCheckRequest* request,
- HealthCheckResponse* response) override {
- std::lock_guard<std::mutex> lock(mu_);
- auto iter = status_map_.find(request->service());
- if (iter == status_map_.end()) {
- return Status(StatusCode::NOT_FOUND, "");
- }
- response->set_status(iter->second);
- return Status::OK;
- }
-
- Status Watch(ServerContext* context, const HealthCheckRequest* request,
- ::grpc::ServerWriter<HealthCheckResponse>* writer) override {
- auto last_state = HealthCheckResponse::UNKNOWN;
- while (!context->IsCancelled()) {
- {
- std::lock_guard<std::mutex> lock(mu_);
- HealthCheckResponse response;
- auto iter = status_map_.find(request->service());
- if (iter == status_map_.end()) {
- response.set_status(response.SERVICE_UNKNOWN);
- } else {
- response.set_status(iter->second);
- }
- if (response.status() != last_state) {
- writer->Write(response, ::grpc::WriteOptions());
- }
- }
- gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
- gpr_time_from_millis(1000, GPR_TIMESPAN)));
- }
- return Status::OK;
- }
-
- void SetStatus(const grpc::string& service_name,
- HealthCheckResponse::ServingStatus status) {
- std::lock_guard<std::mutex> lock(mu_);
- status_map_[service_name] = status;
- }
-
- void SetAll(HealthCheckResponse::ServingStatus status) {
- std::lock_guard<std::mutex> lock(mu_);
- for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) {
- iter->second = status;
- }
- }
-
- private:
- std::mutex mu_;
- std::map<const grpc::string, HealthCheckResponse::ServingStatus> status_map_;
-};
-
// A custom implementation of the health checking service interface. This is
// used to test that it prevents the server from creating a default service and
// also serves as an example of how to override the default service.
@@ -125,6 +70,8 @@ class CustomHealthCheckService : public HealthCheckServiceInterface {
: HealthCheckResponse::NOT_SERVING);
}
+ void Shutdown() override { impl_->Shutdown(); }
+
private:
HealthCheckServiceImpl* impl_; // not owned
};
@@ -260,6 +207,74 @@ class HealthServiceEnd2endTest : public ::testing::Test {
context.TryCancel();
}
+ // Verify that after HealthCheckServiceInterface::Shutdown is called
+ // 1. unary client will see NOT_SERVING.
+ // 2. unary client still sees NOT_SERVING after a SetServing(true) is called.
+ // 3. streaming (Watch) client will see an update.
+ // 4. setting a new service to serving after shutdown will add the service
+ // name but return NOT_SERVING to client.
+ // This has to be called last.
+ void VerifyHealthCheckServiceShutdown() {
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ EXPECT_TRUE(service != nullptr);
+ const grpc::string kHealthyService("healthy_service");
+ const grpc::string kUnhealthyService("unhealthy_service");
+ const grpc::string kNotRegisteredService("not_registered");
+ const grpc::string kNewService("add_after_shutdown");
+ service->SetServingStatus(kHealthyService, true);
+ service->SetServingStatus(kUnhealthyService, false);
+
+ ResetStubs();
+
+ // Start Watch for service.
+ ClientContext context;
+ HealthCheckRequest request;
+ request.set_service(kHealthyService);
+ std::unique_ptr<::grpc::ClientReaderInterface<HealthCheckResponse>> reader =
+ hc_stub_->Watch(&context, request);
+
+ HealthCheckResponse response;
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.SERVING, response.status());
+
+ SendHealthCheckRpc("", Status::OK, HealthCheckResponse::SERVING);
+ SendHealthCheckRpc(kHealthyService, Status::OK,
+ HealthCheckResponse::SERVING);
+ SendHealthCheckRpc(kUnhealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kNotRegisteredService,
+ Status(StatusCode::NOT_FOUND, ""));
+ SendHealthCheckRpc(kNewService, Status(StatusCode::NOT_FOUND, ""));
+
+ // Shutdown health check service.
+ service->Shutdown();
+
+ // Watch client gets another update.
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.NOT_SERVING, response.status());
+ // Finish Watch call.
+ context.TryCancel();
+
+ SendHealthCheckRpc("", Status::OK, HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kHealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kUnhealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kNotRegisteredService,
+ Status(StatusCode::NOT_FOUND, ""));
+
+ // Setting status after Shutdown has no effect.
+ service->SetServingStatus(kHealthyService, true);
+ SendHealthCheckRpc(kHealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+
+ // Adding serving status for a new service after shutdown will return
+ // NOT_SERVING.
+ service->SetServingStatus(kNewService, true);
+ SendHealthCheckRpc(kNewService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ }
+
TestServiceImpl echo_test_service_;
HealthCheckServiceImpl health_check_service_impl_;
std::unique_ptr<Health::Stub> hc_stub_;
@@ -295,6 +310,13 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
Status(StatusCode::INVALID_ARGUMENT, ""));
}
+TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceShutdown) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ SetUpServer(true, false, false, nullptr);
+ VerifyHealthCheckServiceShutdown();
+}
+
// Provide an empty service to disable the default service.
TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) {
EnableDefaultHealthCheckService(true);
@@ -326,12 +348,27 @@ TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) {
VerifyHealthCheckServiceStreaming();
}
+TEST_F(HealthServiceEnd2endTest, ExplicitlyHealthServiceShutdown) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ std::unique_ptr<HealthCheckServiceInterface> override_service(
+ new CustomHealthCheckService(&health_check_service_impl_));
+ HealthCheckServiceInterface* underlying_service = override_service.get();
+ SetUpServer(false, false, true, std::move(override_service));
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ EXPECT_TRUE(service == underlying_service);
+
+ ResetStubs();
+
+ VerifyHealthCheckServiceShutdown();
+}
+
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
index 339eadde92..18bb1ff4b9 100644
--- a/test/cpp/end2end/hybrid_end2end_test.cc
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -894,7 +894,7 @@ TEST_F(HybridEnd2endTest, GenericMethodWithoutGenericService) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/interceptors_util.cc b/test/cpp/end2end/interceptors_util.cc
new file mode 100644
index 0000000000..e0ad7d1526
--- /dev/null
+++ b/test/cpp/end2end/interceptors_util.cc
@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/end2end/interceptors_util.h"
+
+namespace grpc {
+namespace testing {
+
+std::atomic<int> DummyInterceptor::num_times_run_;
+std::atomic<int> DummyInterceptor::num_times_run_reverse_;
+std::atomic<int> DummyInterceptor::num_times_cancel_;
+
+void MakeCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ Status s = stub->Echo(&ctx, req, &resp);
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), "Hello");
+}
+
+void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ string expected_resp = "";
+ auto writer = stub->RequestStream(&ctx, &resp);
+ for (int i = 0; i < 10; i++) {
+ writer->Write(req);
+ expected_resp += "Hello";
+ }
+ writer->WritesDone();
+ Status s = writer->Finish();
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), expected_resp);
+}
+
+void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ string expected_resp = "";
+ auto reader = stub->ResponseStream(&ctx, req);
+ int count = 0;
+ while (reader->Read(&resp)) {
+ EXPECT_EQ(resp.message(), "Hello");
+ count++;
+ }
+ ASSERT_EQ(count, 10);
+ Status s = reader->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ EchoResponse resp;
+ ctx.AddMetadata("testkey", "testvalue");
+ auto stream = stub->BidiStream(&ctx);
+ for (auto i = 0; i < 10; i++) {
+ req.set_message("Hello" + std::to_string(i));
+ stream->Write(req);
+ stream->Read(&resp);
+ EXPECT_EQ(req.message(), resp.message());
+ }
+ ASSERT_TRUE(stream->WritesDone());
+ Status s = stream->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+void MakeCallbackCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ stub->experimental_async()->Echo(&ctx, &req, &resp,
+ [&resp, &mu, &done, &cv](Status s) {
+ // gpr_log(GPR_ERROR, "got the callback");
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), "Hello");
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+}
+
+bool CheckMetadata(const std::multimap<grpc::string_ref, grpc::string_ref>& map,
+ const string& key, const string& value) {
+ for (const auto& pair : map) {
+ if (pair.first.starts_with(key) && pair.second.starts_with(value)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+CreateDummyClientInterceptors() {
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy interceptors before hijacking interceptor
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ return creators;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/end2end/interceptors_util.h b/test/cpp/end2end/interceptors_util.h
new file mode 100644
index 0000000000..d886e32494
--- /dev/null
+++ b/test/cpp/end2end/interceptors_util.h
@@ -0,0 +1,278 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <condition_variable>
+
+#include <grpcpp/channel.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+/* This interceptor does nothing. Just keeps a global count on the number of
+ * times it was invoked. */
+class DummyInterceptor : public experimental::Interceptor {
+ public:
+ DummyInterceptor() {}
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ num_times_run_++;
+ } else if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::
+ POST_RECV_INITIAL_METADATA)) {
+ num_times_run_reverse_++;
+ } else if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CANCEL)) {
+ num_times_cancel_++;
+ }
+ methods->Proceed();
+ }
+
+ static void Reset() {
+ num_times_run_.store(0);
+ num_times_run_reverse_.store(0);
+ num_times_cancel_.store(0);
+ }
+
+ static int GetNumTimesRun() {
+ EXPECT_EQ(num_times_run_.load(), num_times_run_reverse_.load());
+ return num_times_run_.load();
+ }
+
+ static int GetNumTimesCancel() { return num_times_cancel_.load(); }
+
+ private:
+ static std::atomic<int> num_times_run_;
+ static std::atomic<int> num_times_run_reverse_;
+ static std::atomic<int> num_times_cancel_;
+};
+
+class DummyInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface,
+ public experimental::ServerInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new DummyInterceptor();
+ }
+
+ virtual experimental::Interceptor* CreateServerInterceptor(
+ experimental::ServerRpcInfo* info) override {
+ return new DummyInterceptor();
+ }
+};
+
+class EchoTestServiceStreamingImpl : public EchoTestService::Service {
+ public:
+ ~EchoTestServiceStreamingImpl() override {}
+
+ Status BidiStream(
+ ServerContext* context,
+ grpc::ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
+ EchoRequest req;
+ EchoResponse resp;
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ while (stream->Read(&req)) {
+ resp.set_message(req.message());
+ EXPECT_TRUE(stream->Write(resp, grpc::WriteOptions()));
+ }
+ return Status::OK;
+ }
+
+ Status RequestStream(ServerContext* context,
+ ServerReader<EchoRequest>* reader,
+ EchoResponse* resp) override {
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ EchoRequest req;
+ string response_str = "";
+ while (reader->Read(&req)) {
+ response_str += req.message();
+ }
+ resp->set_message(response_str);
+ return Status::OK;
+ }
+
+ Status ResponseStream(ServerContext* context, const EchoRequest* req,
+ ServerWriter<EchoResponse>* writer) override {
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ EchoResponse resp;
+ resp.set_message(req->message());
+ for (int i = 0; i < 10; i++) {
+ EXPECT_TRUE(writer->Write(resp));
+ }
+ return Status::OK;
+ }
+};
+
+void MakeCall(const std::shared_ptr<Channel>& channel);
+
+void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeCallbackCall(const std::shared_ptr<Channel>& channel);
+
+bool CheckMetadata(const std::multimap<grpc::string_ref, grpc::string_ref>& map,
+ const string& key, const string& value);
+
+std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+CreateDummyClientInterceptors();
+
+inline void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
+inline int detag(void* p) {
+ return static_cast<int>(reinterpret_cast<intptr_t>(p));
+}
+
+class Verifier {
+ public:
+ Verifier() : lambda_run_(false) {}
+ // Expect sets the expected ok value for a specific tag
+ Verifier& Expect(int i, bool expect_ok) {
+ return ExpectUnless(i, expect_ok, false);
+ }
+ // ExpectUnless sets the expected ok value for a specific tag
+ // unless the tag was already marked seen (as a result of ExpectMaybe)
+ Verifier& ExpectUnless(int i, bool expect_ok, bool seen) {
+ if (!seen) {
+ expectations_[tag(i)] = expect_ok;
+ }
+ return *this;
+ }
+ // ExpectMaybe sets the expected ok value for a specific tag, but does not
+ // require it to appear
+ // If it does, sets *seen to true
+ Verifier& ExpectMaybe(int i, bool expect_ok, bool* seen) {
+ if (!*seen) {
+ maybe_expectations_[tag(i)] = MaybeExpect{expect_ok, seen};
+ }
+ return *this;
+ }
+
+ // Next waits for 1 async tag to complete, checks its
+ // expectations, and returns the tag
+ int Next(CompletionQueue* cq, bool ignore_ok) {
+ bool ok;
+ void* got_tag;
+ EXPECT_TRUE(cq->Next(&got_tag, &ok));
+ GotTag(got_tag, ok, ignore_ok);
+ return detag(got_tag);
+ }
+
+ template <typename T>
+ CompletionQueue::NextStatus DoOnceThenAsyncNext(
+ CompletionQueue* cq, void** got_tag, bool* ok, T deadline,
+ std::function<void(void)> lambda) {
+ if (lambda_run_) {
+ return cq->AsyncNext(got_tag, ok, deadline);
+ } else {
+ lambda_run_ = true;
+ return cq->DoThenAsyncNext(lambda, got_tag, ok, deadline);
+ }
+ }
+
+ // Verify keeps calling Next until all currently set
+ // expected tags are complete
+ void Verify(CompletionQueue* cq) { Verify(cq, false); }
+
+ // This version of Verify allows optionally ignoring the
+ // outcome of the expectation
+ void Verify(CompletionQueue* cq, bool ignore_ok) {
+ GPR_ASSERT(!expectations_.empty() || !maybe_expectations_.empty());
+ while (!expectations_.empty()) {
+ Next(cq, ignore_ok);
+ }
+ }
+
+ // This version of Verify stops after a certain deadline, and uses the
+ // DoThenAsyncNext API
+ // to call the lambda
+ void Verify(CompletionQueue* cq,
+ std::chrono::system_clock::time_point deadline,
+ const std::function<void(void)>& lambda) {
+ if (expectations_.empty()) {
+ bool ok;
+ void* got_tag;
+ EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+ CompletionQueue::TIMEOUT);
+ } else {
+ while (!expectations_.empty()) {
+ bool ok;
+ void* got_tag;
+ EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+ CompletionQueue::GOT_EVENT);
+ GotTag(got_tag, ok, false);
+ }
+ }
+ }
+
+ private:
+ void GotTag(void* got_tag, bool ok, bool ignore_ok) {
+ auto it = expectations_.find(got_tag);
+ if (it != expectations_.end()) {
+ if (!ignore_ok) {
+ EXPECT_EQ(it->second, ok);
+ }
+ expectations_.erase(it);
+ } else {
+ auto it2 = maybe_expectations_.find(got_tag);
+ if (it2 != maybe_expectations_.end()) {
+ if (it2->second.seen != nullptr) {
+ EXPECT_FALSE(*it2->second.seen);
+ *it2->second.seen = true;
+ }
+ if (!ignore_ok) {
+ EXPECT_EQ(it2->second.ok, ok);
+ }
+ } else {
+ gpr_log(GPR_ERROR, "Unexpected tag: %p", got_tag);
+ abort();
+ }
+ }
+ }
+
+ struct MaybeExpect {
+ bool ok;
+ bool* seen;
+ };
+
+ std::map<void*, bool> expectations_;
+ std::map<void*, MaybeExpect> maybe_expectations_;
+ bool lambda_run_;
+};
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index ba3122c895..917ca28020 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -345,7 +345,7 @@ TEST_F(MockTest, BidiStream) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/nonblocking_test.cc b/test/cpp/end2end/nonblocking_test.cc
index d8337baca2..36dea1fcb3 100644
--- a/test/cpp/end2end/nonblocking_test.cc
+++ b/test/cpp/end2end/nonblocking_test.cc
@@ -187,7 +187,7 @@ int main(int argc, char** argv) {
grpc_poll_function = maybe_assert_non_blocking_poll;
#endif // GRPC_POSIX_SOCKET
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc
index 21a275ef62..ff097aa9a7 100644
--- a/test/cpp/end2end/proto_server_reflection_test.cc
+++ b/test/cpp/end2end/proto_server_reflection_test.cc
@@ -144,7 +144,7 @@ TEST_F(ProtoServerReflectionTest, CheckResponseWithLocalDescriptorPool) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/raw_end2end_test.cc b/test/cpp/end2end/raw_end2end_test.cc
index a413905ef7..c8556bae95 100644
--- a/test/cpp/end2end/raw_end2end_test.cc
+++ b/test/cpp/end2end/raw_end2end_test.cc
@@ -363,7 +363,7 @@ TEST_F(RawEnd2EndTest, CompileTest) {
int main(int argc, char** argv) {
// Change the backup poll interval from 5s to 100ms to speed up the
// ReconnectChannel test
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc
index d54523fcbb..d744a93912 100644
--- a/test/cpp/end2end/server_builder_plugin_test.cc
+++ b/test/cpp/end2end/server_builder_plugin_test.cc
@@ -264,7 +264,7 @@ INSTANTIATE_TEST_CASE_P(ServerBuilderPluginTest, ServerBuilderPluginTest,
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/server_crash_test.cc b/test/cpp/end2end/server_crash_test.cc
index 93257b2705..353ebf713a 100644
--- a/test/cpp/end2end/server_crash_test.cc
+++ b/test/cpp/end2end/server_crash_test.cc
@@ -153,7 +153,7 @@ int main(int argc, char** argv) {
g_root = ".";
}
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/server_early_return_test.cc b/test/cpp/end2end/server_early_return_test.cc
index 8948e5b854..c47e25052e 100644
--- a/test/cpp/end2end/server_early_return_test.cc
+++ b/test/cpp/end2end/server_early_return_test.cc
@@ -226,7 +226,7 @@ TEST_F(ServerEarlyReturnTest, RequestStreamEarlyCancel) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc
new file mode 100644
index 0000000000..9460a7d6c6
--- /dev/null
+++ b/test/cpp/end2end/server_interceptors_end2end_test.cc
@@ -0,0 +1,610 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <memory>
+#include <vector>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class LoggingInterceptor : public experimental::Interceptor {
+ public:
+ LoggingInterceptor(experimental::ServerRpcInfo* info) {
+ info_ = info;
+
+ // Check the method name and compare to the type
+ const char* method = info->method();
+ experimental::ServerRpcInfo::Type type = info->type();
+
+ // Check that we use one of our standard methods with expected type.
+ // Also allow the health checking service.
+ // We accept BIDI_STREAMING for Echo in case it's an AsyncGenericService
+ // being tested (the GenericRpc test).
+ // The empty method is for the Unimplemented requests that arise
+ // when draining the CQ.
+ EXPECT_TRUE(
+ strstr(method, "/grpc.health") == method ||
+ (strcmp(method, "/grpc.testing.EchoTestService/Echo") == 0 &&
+ (type == experimental::ServerRpcInfo::Type::UNARY ||
+ type == experimental::ServerRpcInfo::Type::BIDI_STREAMING)) ||
+ (strcmp(method, "/grpc.testing.EchoTestService/RequestStream") == 0 &&
+ type == experimental::ServerRpcInfo::Type::CLIENT_STREAMING) ||
+ (strcmp(method, "/grpc.testing.EchoTestService/ResponseStream") == 0 &&
+ type == experimental::ServerRpcInfo::Type::SERVER_STREAMING) ||
+ (strcmp(method, "/grpc.testing.EchoTestService/BidiStream") == 0 &&
+ type == experimental::ServerRpcInfo::Type::BIDI_STREAMING) ||
+ strcmp(method, "/grpc.testing.EchoTestService/Unimplemented") == 0 ||
+ (strcmp(method, "") == 0 &&
+ type == experimental::ServerRpcInfo::Type::BIDI_STREAMING));
+ }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_TRUE(req.message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_STATUS)) {
+ auto* map = methods->GetSendTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.find("testkey") == 0 &&
+ pair.second.find("testvalue") == 0;
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto status = methods->GetSendStatus();
+ EXPECT_EQ(status.ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.find("testkey") == 0 &&
+ pair.second.find("testvalue") == 0;
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ EXPECT_TRUE(resp->message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_CLOSE)) {
+ // Got nothing interesting to do here
+ }
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ServerRpcInfo* info_;
+};
+
+class LoggingInterceptorFactory
+ : public experimental::ServerInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateServerInterceptor(
+ experimental::ServerRpcInfo* info) override {
+ return new LoggingInterceptor(info);
+ }
+};
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ EchoResponse resp;
+ ctx.AddMetadata("testkey", "testvalue");
+ auto stream = stub->BidiStream(&ctx);
+ for (auto i = 0; i < 10; i++) {
+ req.set_message("Hello" + std::to_string(i));
+ stream->Write(req);
+ stream->Read(&resp);
+ EXPECT_EQ(req.message(), resp.message());
+ }
+ ASSERT_TRUE(stream->WritesDone());
+ Status s = stream->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+class ServerInterceptorsEnd2endSyncUnaryTest : public ::testing::Test {
+ protected:
+ ServerInterceptorsEnd2endSyncUnaryTest() {
+ int port = grpc_pick_unused_port_or_die();
+
+ ServerBuilder builder;
+ server_address_ = "localhost:" + std::to_string(port);
+ builder.AddListeningPort(server_address_, InsecureServerCredentials());
+ builder.RegisterService(&service_);
+
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ server_ = builder.BuildAndStart();
+ }
+ std::string server_address_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ServerInterceptorsEnd2endSyncUnaryTest, UnaryTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ServerInterceptorsEnd2endSyncStreamingTest : public ::testing::Test {
+ protected:
+ ServerInterceptorsEnd2endSyncStreamingTest() {
+ int port = grpc_pick_unused_port_or_die();
+
+ ServerBuilder builder;
+ server_address_ = "localhost:" + std::to_string(port);
+ builder.AddListeningPort(server_address_, InsecureServerCredentials());
+ builder.RegisterService(&service_);
+
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ server_ = builder.BuildAndStart();
+ }
+ std::string server_address_;
+ EchoTestServiceStreamingImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ClientStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeClientStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ServerStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeServerStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, BidiStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeBidiStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ServerInterceptorsAsyncEnd2endTest : public ::testing::Test {};
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, UnaryTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ EchoTestService::AsyncService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+ std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+ stub->AsyncEcho(&cli_ctx, send_request, cq.get()));
+
+ service.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq.get(),
+ cq.get(), tag(2));
+
+ response_reader->Finish(&recv_response, &recv_status, tag(4));
+
+ Verifier().Expect(2, true).Verify(cq.get());
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ send_response.set_message(recv_request.message());
+ response_writer.Finish(send_response, Status::OK, tag(3));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq.get());
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, BidiStreamingTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ EchoTestService::AsyncService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+ std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
+ cli_stream(stub->AsyncBidiStream(&cli_ctx, cq.get(), tag(1)));
+
+ service.RequestBidiStream(&srv_ctx, &srv_stream, cq.get(), cq.get(), tag(2));
+
+ Verifier().Expect(1, true).Expect(2, true).Verify(cq.get());
+
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ cli_stream->Write(send_request, tag(3));
+ srv_stream.Read(&recv_request, tag(4));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq.get());
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ srv_stream.Write(send_response, tag(5));
+ cli_stream->Read(&recv_response, tag(6));
+ Verifier().Expect(5, true).Expect(6, true).Verify(cq.get());
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ cli_stream->WritesDone(tag(7));
+ srv_stream.Read(&recv_request, tag(8));
+ Verifier().Expect(7, true).Expect(8, false).Verify(cq.get());
+
+ srv_stream.Finish(Status::OK, tag(9));
+ cli_stream->Finish(&recv_status, tag(10));
+ Verifier().Expect(9, true).Expect(10, true).Verify(cq.get());
+
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, GenericRPCTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ AsyncGenericService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterAsyncGenericService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ GenericStub generic_stub(channel);
+
+ const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ GenericServerContext srv_ctx;
+ GenericServerAsyncReaderWriter stream(&srv_ctx);
+
+ // The string needs to be long enough to test heap-based slice.
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+
+ std::unique_ptr<GenericClientAsyncReaderWriter> call =
+ generic_stub.PrepareCall(&cli_ctx, kMethodName, cq.get());
+ call->StartCall(tag(1));
+ Verifier().Expect(1, true).Verify(cq.get());
+ std::unique_ptr<ByteBuffer> send_buffer =
+ SerializeToByteBuffer(&send_request);
+ call->Write(*send_buffer, tag(2));
+ // Send ByteBuffer can be destroyed after calling Write.
+ send_buffer.reset();
+ Verifier().Expect(2, true).Verify(cq.get());
+ call->WritesDone(tag(3));
+ Verifier().Expect(3, true).Verify(cq.get());
+
+ service.RequestCall(&srv_ctx, &stream, cq.get(), cq.get(), tag(4));
+
+ Verifier().Expect(4, true).Verify(cq.get());
+ EXPECT_EQ(kMethodName, srv_ctx.method());
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ ByteBuffer recv_buffer;
+ stream.Read(&recv_buffer, tag(5));
+ Verifier().Expect(5, true).Verify(cq.get());
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ send_buffer = SerializeToByteBuffer(&send_response);
+ stream.Write(*send_buffer, tag(6));
+ send_buffer.reset();
+ Verifier().Expect(6, true).Verify(cq.get());
+
+ stream.Finish(Status::OK, tag(7));
+ Verifier().Expect(7, true).Verify(cq.get());
+
+ recv_buffer.Clear();
+ call->Read(&recv_buffer, tag(8));
+ Verifier().Expect(8, true).Verify(cq.get());
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
+
+ call->Finish(&recv_status, tag(9));
+ Verifier().Expect(9, true).Verify(cq.get());
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, UnimplementedRpcTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ std::shared_ptr<Channel> channel =
+ CreateChannel(server_address, InsecureChannelCredentials());
+ std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
+ stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
+ EchoRequest send_request;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ send_request.set_message("Hello");
+ std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+ stub->AsyncUnimplemented(&cli_ctx, send_request, cq.get()));
+
+ response_reader->Finish(&recv_response, &recv_status, tag(4));
+ Verifier().Expect(4, true).Verify(cq.get());
+
+ EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
+ EXPECT_EQ("", recv_status.error_message());
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+class ServerInterceptorsSyncUnimplementedEnd2endTest : public ::testing::Test {
+};
+
+TEST_F(ServerInterceptorsSyncUnimplementedEnd2endTest, UnimplementedRpcTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ TestServiceImpl service;
+ builder.RegisterService(&service);
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ std::shared_ptr<Channel> channel =
+ CreateChannel(server_address, InsecureChannelCredentials());
+ std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
+ stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
+ EchoRequest send_request;
+ EchoResponse recv_response;
+
+ ClientContext cli_ctx;
+ send_request.set_message("Hello");
+ Status recv_status =
+ stub->Unimplemented(&cli_ctx, send_request, &recv_response);
+
+ EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
+ EXPECT_EQ("", recv_status.error_message());
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ grpc_recycle_unused_port(port);
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc
index a53de691bc..da42178d67 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -164,7 +164,7 @@ TEST_P(ShutdownTest, ShutdownTest) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/streaming_throughput_test.cc b/test/cpp/end2end/streaming_throughput_test.cc
index 898d1ec118..440656588b 100644
--- a/test/cpp/end2end/streaming_throughput_test.cc
+++ b/test/cpp/end2end/streaming_throughput_test.cc
@@ -187,7 +187,7 @@ TEST_F(End2endTest, StreamingThroughput) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/end2end/test_health_check_service_impl.cc b/test/cpp/end2end/test_health_check_service_impl.cc
new file mode 100644
index 0000000000..0801e30199
--- /dev/null
+++ b/test/cpp/end2end/test_health_check_service_impl.cc
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/end2end/test_health_check_service_impl.h"
+
+#include <grpc/grpc.h>
+
+using grpc::health::v1::HealthCheckRequest;
+using grpc::health::v1::HealthCheckResponse;
+
+namespace grpc {
+namespace testing {
+
+Status HealthCheckServiceImpl::Check(ServerContext* context,
+ const HealthCheckRequest* request,
+ HealthCheckResponse* response) {
+ std::lock_guard<std::mutex> lock(mu_);
+ auto iter = status_map_.find(request->service());
+ if (iter == status_map_.end()) {
+ return Status(StatusCode::NOT_FOUND, "");
+ }
+ response->set_status(iter->second);
+ return Status::OK;
+}
+
+Status HealthCheckServiceImpl::Watch(
+ ServerContext* context, const HealthCheckRequest* request,
+ ::grpc::ServerWriter<HealthCheckResponse>* writer) {
+ auto last_state = HealthCheckResponse::UNKNOWN;
+ while (!context->IsCancelled()) {
+ {
+ std::lock_guard<std::mutex> lock(mu_);
+ HealthCheckResponse response;
+ auto iter = status_map_.find(request->service());
+ if (iter == status_map_.end()) {
+ response.set_status(response.SERVICE_UNKNOWN);
+ } else {
+ response.set_status(iter->second);
+ }
+ if (response.status() != last_state) {
+ writer->Write(response, ::grpc::WriteOptions());
+ }
+ }
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_millis(1000, GPR_TIMESPAN)));
+ }
+ return Status::OK;
+}
+
+void HealthCheckServiceImpl::SetStatus(
+ const grpc::string& service_name,
+ HealthCheckResponse::ServingStatus status) {
+ std::lock_guard<std::mutex> lock(mu_);
+ if (shutdown_) {
+ status = HealthCheckResponse::NOT_SERVING;
+ }
+ status_map_[service_name] = status;
+}
+
+void HealthCheckServiceImpl::SetAll(HealthCheckResponse::ServingStatus status) {
+ std::lock_guard<std::mutex> lock(mu_);
+ if (shutdown_) {
+ return;
+ }
+ for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) {
+ iter->second = status;
+ }
+}
+
+void HealthCheckServiceImpl::Shutdown() {
+ std::lock_guard<std::mutex> lock(mu_);
+ if (shutdown_) {
+ return;
+ }
+ shutdown_ = true;
+ for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) {
+ iter->second = HealthCheckResponse::NOT_SERVING;
+ }
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/end2end/test_health_check_service_impl.h b/test/cpp/end2end/test_health_check_service_impl.h
new file mode 100644
index 0000000000..5d36ce5320
--- /dev/null
+++ b/test/cpp/end2end/test_health_check_service_impl.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H
+#define GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H
+
+#include <map>
+#include <mutex>
+
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "src/proto/grpc/health/v1/health.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+// A sample sync implementation of the health checking service. This does the
+// same thing as the default one.
+class HealthCheckServiceImpl : public health::v1::Health::Service {
+ public:
+ Status Check(ServerContext* context,
+ const health::v1::HealthCheckRequest* request,
+ health::v1::HealthCheckResponse* response) override;
+ Status Watch(ServerContext* context,
+ const health::v1::HealthCheckRequest* request,
+ ServerWriter<health::v1::HealthCheckResponse>* writer) override;
+ void SetStatus(const grpc::string& service_name,
+ health::v1::HealthCheckResponse::ServingStatus status);
+ void SetAll(health::v1::HealthCheckResponse::ServingStatus status);
+
+ void Shutdown();
+
+ private:
+ std::mutex mu_;
+ bool shutdown_ = false;
+ std::map<const grpc::string, health::v1::HealthCheckResponse::ServingStatus>
+ status_map_;
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index 3c3a5d9cd4..6729ad14f4 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -69,6 +69,62 @@ void CheckServerAuthContext(
EXPECT_EQ(expected_client_identity, identity[0]);
}
}
+
+// Returns the number of pairs in metadata that exactly match the given
+// key-value pair. Returns -1 if the pair wasn't found.
+int MetadataMatchCount(
+ const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
+ const grpc::string& key, const grpc::string& value) {
+ int count = 0;
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator iter =
+ metadata.begin();
+ iter != metadata.end(); ++iter) {
+ if (ToString(iter->first) == key && ToString(iter->second) == value) {
+ count++;
+ }
+ }
+ return count;
+}
+} // namespace
+
+namespace {
+int GetIntValueFromMetadataHelper(
+ const char* key,
+ const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
+ int default_value) {
+ if (metadata.find(key) != metadata.end()) {
+ std::istringstream iss(ToString(metadata.find(key)->second));
+ iss >> default_value;
+ gpr_log(GPR_INFO, "%s : %d", key, default_value);
+ }
+
+ return default_value;
+}
+
+int GetIntValueFromMetadata(
+ const char* key,
+ const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
+ int default_value) {
+ return GetIntValueFromMetadataHelper(key, metadata, default_value);
+}
+
+void ServerTryCancel(ServerContext* context) {
+ EXPECT_FALSE(context->IsCancelled());
+ context->TryCancel();
+ gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request");
+ // Now wait until it's really canceled
+ while (!context->IsCancelled()) {
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(1000, GPR_TIMESPAN)));
+ }
+}
+
+void ServerTryCancelNonblocking(ServerContext* context) {
+ EXPECT_FALSE(context->IsCancelled());
+ context->TryCancel();
+ gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request");
+}
+
} // namespace
Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
@@ -165,6 +221,166 @@ Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
return Status::OK;
}
+Status TestServiceImpl::CheckClientInitialMetadata(ServerContext* context,
+ const SimpleRequest* request,
+ SimpleResponse* response) {
+ EXPECT_EQ(MetadataMatchCount(context->client_metadata(),
+ kCheckClientInitialMetadataKey,
+ kCheckClientInitialMetadataVal),
+ 1);
+ EXPECT_EQ(1u,
+ context->client_metadata().count(kCheckClientInitialMetadataKey));
+ return Status::OK;
+}
+
+void CallbackTestServiceImpl::Echo(
+ ServerContext* context, const EchoRequest* request, EchoResponse* response,
+ experimental::ServerCallbackRpcController* controller) {
+ // A bit of sleep to make sure that short deadline tests fail
+ if (request->has_param() && request->param().server_sleep_us() > 0) {
+ // Set an alarm for that much time
+ alarm_.experimental().Set(
+ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_micros(request->param().server_sleep_us(),
+ GPR_TIMESPAN)),
+ [this, context, request, response, controller](bool) {
+ EchoNonDelayed(context, request, response, controller);
+ });
+ } else {
+ EchoNonDelayed(context, request, response, controller);
+ }
+}
+
+void CallbackTestServiceImpl::CheckClientInitialMetadata(
+ ServerContext* context, const SimpleRequest* request,
+ SimpleResponse* response,
+ experimental::ServerCallbackRpcController* controller) {
+ EXPECT_EQ(MetadataMatchCount(context->client_metadata(),
+ kCheckClientInitialMetadataKey,
+ kCheckClientInitialMetadataVal),
+ 1);
+ EXPECT_EQ(1u,
+ context->client_metadata().count(kCheckClientInitialMetadataKey));
+ controller->Finish(Status::OK);
+}
+
+void CallbackTestServiceImpl::EchoNonDelayed(
+ ServerContext* context, const EchoRequest* request, EchoResponse* response,
+ experimental::ServerCallbackRpcController* controller) {
+ if (request->has_param() && request->param().server_die()) {
+ gpr_log(GPR_ERROR, "The request should not reach application handler.");
+ GPR_ASSERT(0);
+ }
+ if (request->has_param() && request->param().has_expected_error()) {
+ const auto& error = request->param().expected_error();
+ controller->Finish(Status(static_cast<StatusCode>(error.code()),
+ error.error_message(),
+ error.binary_error_details()));
+ return;
+ }
+ int server_try_cancel = GetIntValueFromMetadata(
+ kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+ if (server_try_cancel > DO_NOT_CANCEL) {
+ // Since this is a unary RPC, by the time this server handler is called,
+ // the 'request' message is already read from the client. So the scenarios
+ // in server_try_cancel don't make much sense. Just cancel the RPC as long
+ // as server_try_cancel is not DO_NOT_CANCEL
+ EXPECT_FALSE(context->IsCancelled());
+ context->TryCancel();
+ gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request");
+ // Now wait until it's really canceled
+
+ std::function<void(bool)> recurrence = [this, context, controller,
+ &recurrence](bool) {
+ if (!context->IsCancelled()) {
+ alarm_.experimental().Set(
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(1000, GPR_TIMESPAN)),
+ recurrence);
+ } else {
+ controller->Finish(Status::CANCELLED);
+ }
+ };
+ recurrence(true);
+ return;
+ }
+
+ gpr_log(GPR_DEBUG, "Request message was %s", request->message().c_str());
+ response->set_message(request->message());
+ MaybeEchoDeadline(context, request, response);
+ if (host_) {
+ response->mutable_param()->set_host(*host_);
+ }
+ if (request->has_param() && request->param().client_cancel_after_us()) {
+ {
+ std::unique_lock<std::mutex> lock(mu_);
+ signal_client_ = true;
+ }
+ std::function<void(bool)> recurrence = [this, context, request, controller,
+ &recurrence](bool) {
+ if (!context->IsCancelled()) {
+ alarm_.experimental().Set(
+ gpr_time_add(
+ gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(request->param().client_cancel_after_us(),
+ GPR_TIMESPAN)),
+ recurrence);
+ } else {
+ controller->Finish(Status::CANCELLED);
+ }
+ };
+ recurrence(true);
+ return;
+ } else if (request->has_param() &&
+ request->param().server_cancel_after_us()) {
+ alarm_.experimental().Set(
+ gpr_time_add(
+ gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(request->param().server_cancel_after_us(),
+ GPR_TIMESPAN)),
+ [controller](bool) { controller->Finish(Status::CANCELLED); });
+ return;
+ } else if (!request->has_param() ||
+ !request->param().skip_cancelled_check()) {
+ EXPECT_FALSE(context->IsCancelled());
+ }
+
+ if (request->has_param() && request->param().echo_metadata()) {
+ const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata =
+ context->client_metadata();
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = client_metadata.begin();
+ iter != client_metadata.end(); ++iter) {
+ context->AddTrailingMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ // Terminate rpc with error and debug info in trailer.
+ if (request->param().debug_info().stack_entries_size() ||
+ !request->param().debug_info().detail().empty()) {
+ grpc::string serialized_debug_info =
+ request->param().debug_info().SerializeAsString();
+ context->AddTrailingMetadata(kDebugInfoTrailerKey, serialized_debug_info);
+ controller->Finish(Status::CANCELLED);
+ return;
+ }
+ }
+ if (request->has_param() &&
+ (request->param().expected_client_identity().length() > 0 ||
+ request->param().check_auth_context())) {
+ CheckServerAuthContext(context,
+ request->param().expected_transport_security_type(),
+ request->param().expected_client_identity());
+ }
+ if (request->has_param() && request->param().response_message_length() > 0) {
+ response->set_message(
+ grpc::string(request->param().response_message_length(), '\0'));
+ }
+ if (request->has_param() && request->param().echo_peer()) {
+ response->mutable_param()->set_peer(context->peer());
+ }
+ controller->Finish(Status::OK);
+}
+
// Unimplemented is left unimplemented to test the returned error.
Status TestServiceImpl::RequestStream(ServerContext* context,
@@ -192,7 +408,7 @@ Status TestServiceImpl::RequestStream(ServerContext* context,
std::thread* server_try_cancel_thd = nullptr;
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
- new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+ new std::thread([context] { ServerTryCancel(context); });
}
int num_msgs_read = 0;
@@ -247,7 +463,7 @@ Status TestServiceImpl::ResponseStream(ServerContext* context,
std::thread* server_try_cancel_thd = nullptr;
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
- new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+ new std::thread([context] { ServerTryCancel(context); });
}
for (int i = 0; i < server_responses_to_send; i++) {
@@ -298,7 +514,7 @@ Status TestServiceImpl::BidiStream(
std::thread* server_try_cancel_thd = nullptr;
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
- new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+ new std::thread([context] { ServerTryCancel(context); });
}
// kServerFinishAfterNReads suggests after how many reads, the server should
@@ -332,28 +548,244 @@ Status TestServiceImpl::BidiStream(
return Status::OK;
}
-int TestServiceImpl::GetIntValueFromMetadata(
- const char* key,
- const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
- int default_value) {
- if (metadata.find(key) != metadata.end()) {
- std::istringstream iss(ToString(metadata.find(key)->second));
- iss >> default_value;
- gpr_log(GPR_INFO, "%s : %d", key, default_value);
- }
+experimental::ServerReadReactor<EchoRequest, EchoResponse>*
+CallbackTestServiceImpl::RequestStream() {
+ class Reactor : public ::grpc::experimental::ServerReadReactor<EchoRequest,
+ EchoResponse> {
+ public:
+ Reactor() {}
+ void OnStarted(ServerContext* context, EchoResponse* response) override {
+ ctx_ = context;
+ response_ = response;
+ // If 'server_try_cancel' is set in the metadata, the RPC is cancelled by
+ // the server by calling ServerContext::TryCancel() depending on the
+ // value:
+ // CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server
+ // reads any message from the client CANCEL_DURING_PROCESSING: The RPC
+ // is cancelled while the server is reading messages from the client
+ // CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server reads
+ // all the messages from the client
+ server_try_cancel_ = GetIntValueFromMetadata(
+ kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+
+ response_->set_message("");
+
+ if (server_try_cancel_ == CANCEL_BEFORE_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ return;
+ }
+
+ if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ ctx_->TryCancel();
+ // Don't wait for it here
+ }
+
+ StartRead(&request_);
+ }
+ void OnDone() override { delete this; }
+ void OnCancel() override { FinishOnce(Status::CANCELLED); }
+ void OnReadDone(bool ok) override {
+ if (ok) {
+ response_->mutable_message()->append(request_.message());
+ num_msgs_read_++;
+ StartRead(&request_);
+ } else {
+ gpr_log(GPR_INFO, "Read: %d messages", num_msgs_read_);
+
+ if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ // Let OnCancel recover this
+ return;
+ }
+ if (server_try_cancel_ == CANCEL_AFTER_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ return;
+ }
+ FinishOnce(Status::OK);
+ }
+ }
- return default_value;
+ private:
+ void FinishOnce(const Status& s) {
+ std::lock_guard<std::mutex> l(finish_mu_);
+ if (!finished_) {
+ Finish(s);
+ finished_ = true;
+ }
+ }
+
+ ServerContext* ctx_;
+ EchoResponse* response_;
+ EchoRequest request_;
+ int num_msgs_read_{0};
+ int server_try_cancel_;
+ std::mutex finish_mu_;
+ bool finished_{false};
+ };
+
+ return new Reactor;
}
-void TestServiceImpl::ServerTryCancel(ServerContext* context) {
- EXPECT_FALSE(context->IsCancelled());
- context->TryCancel();
- gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request");
- // Now wait until it's really canceled
- while (!context->IsCancelled()) {
- gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_micros(1000, GPR_TIMESPAN)));
- }
+// Return 'kNumResponseStreamMsgs' messages.
+// TODO(yangg) make it generic by adding a parameter into EchoRequest
+experimental::ServerWriteReactor<EchoRequest, EchoResponse>*
+CallbackTestServiceImpl::ResponseStream() {
+ class Reactor
+ : public ::grpc::experimental::ServerWriteReactor<EchoRequest,
+ EchoResponse> {
+ public:
+ Reactor() {}
+ void OnStarted(ServerContext* context,
+ const EchoRequest* request) override {
+ ctx_ = context;
+ request_ = request;
+ // If 'server_try_cancel' is set in the metadata, the RPC is cancelled by
+ // the server by calling ServerContext::TryCancel() depending on the
+ // value:
+ // CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server
+ // reads any message from the client CANCEL_DURING_PROCESSING: The RPC
+ // is cancelled while the server is reading messages from the client
+ // CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server reads
+ // all the messages from the client
+ server_try_cancel_ = GetIntValueFromMetadata(
+ kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+ server_coalescing_api_ = GetIntValueFromMetadata(
+ kServerUseCoalescingApi, context->client_metadata(), 0);
+ server_responses_to_send_ = GetIntValueFromMetadata(
+ kServerResponseStreamsToSend, context->client_metadata(),
+ kServerDefaultResponseStreamsToSend);
+ if (server_try_cancel_ == CANCEL_BEFORE_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ return;
+ }
+
+ if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ ctx_->TryCancel();
+ }
+ if (num_msgs_sent_ < server_responses_to_send_) {
+ NextWrite();
+ }
+ }
+ void OnDone() override { delete this; }
+ void OnCancel() override { FinishOnce(Status::CANCELLED); }
+ void OnWriteDone(bool ok) override {
+ if (num_msgs_sent_ < server_responses_to_send_) {
+ NextWrite();
+ } else if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ // Let OnCancel recover this
+ } else if (server_try_cancel_ == CANCEL_AFTER_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ } else {
+ FinishOnce(Status::OK);
+ }
+ }
+
+ private:
+ void FinishOnce(const Status& s) {
+ std::lock_guard<std::mutex> l(finish_mu_);
+ if (!finished_) {
+ Finish(s);
+ finished_ = true;
+ }
+ }
+
+ void NextWrite() {
+ response_.set_message(request_->message() +
+ grpc::to_string(num_msgs_sent_));
+ if (num_msgs_sent_ == server_responses_to_send_ - 1 &&
+ server_coalescing_api_ != 0) {
+ num_msgs_sent_++;
+ StartWriteLast(&response_, WriteOptions());
+ } else {
+ num_msgs_sent_++;
+ StartWrite(&response_);
+ }
+ }
+ ServerContext* ctx_;
+ const EchoRequest* request_;
+ EchoResponse response_;
+ int num_msgs_sent_{0};
+ int server_try_cancel_;
+ int server_coalescing_api_;
+ int server_responses_to_send_;
+ std::mutex finish_mu_;
+ bool finished_{false};
+ };
+ return new Reactor;
+}
+
+experimental::ServerBidiReactor<EchoRequest, EchoResponse>*
+CallbackTestServiceImpl::BidiStream() {
+ class Reactor : public ::grpc::experimental::ServerBidiReactor<EchoRequest,
+ EchoResponse> {
+ public:
+ Reactor() {}
+ void OnStarted(ServerContext* context) override {
+ ctx_ = context;
+ // If 'server_try_cancel' is set in the metadata, the RPC is cancelled by
+ // the server by calling ServerContext::TryCancel() depending on the
+ // value:
+ // CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server
+ // reads any message from the client CANCEL_DURING_PROCESSING: The RPC
+ // is cancelled while the server is reading messages from the client
+ // CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server reads
+ // all the messages from the client
+ server_try_cancel_ = GetIntValueFromMetadata(
+ kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+ server_write_last_ = GetIntValueFromMetadata(
+ kServerFinishAfterNReads, context->client_metadata(), 0);
+ if (server_try_cancel_ == CANCEL_BEFORE_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ return;
+ }
+
+ if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ ctx_->TryCancel();
+ }
+
+ StartRead(&request_);
+ }
+ void OnDone() override { delete this; }
+ void OnCancel() override { FinishOnce(Status::CANCELLED); }
+ void OnReadDone(bool ok) override {
+ if (ok) {
+ num_msgs_read_++;
+ gpr_log(GPR_INFO, "recv msg %s", request_.message().c_str());
+ response_.set_message(request_.message());
+ if (num_msgs_read_ == server_write_last_) {
+ StartWriteLast(&response_, WriteOptions());
+ } else {
+ StartWrite(&response_);
+ }
+ } else if (server_try_cancel_ == CANCEL_DURING_PROCESSING) {
+ // Let OnCancel handle this
+ } else if (server_try_cancel_ == CANCEL_AFTER_PROCESSING) {
+ ServerTryCancelNonblocking(ctx_);
+ } else {
+ FinishOnce(Status::OK);
+ }
+ }
+ void OnWriteDone(bool ok) override { StartRead(&request_); }
+
+ private:
+ void FinishOnce(const Status& s) {
+ std::lock_guard<std::mutex> l(finish_mu_);
+ if (!finished_) {
+ Finish(s);
+ finished_ = true;
+ }
+ }
+
+ ServerContext* ctx_;
+ EchoRequest request_;
+ EchoResponse response_;
+ int num_msgs_read_{0};
+ int server_try_cancel_;
+ int server_write_last_;
+ std::mutex finish_mu_;
+ bool finished_{false};
+ };
+
+ return new Reactor;
}
} // namespace testing
diff --git a/test/cpp/end2end/test_service_impl.h b/test/cpp/end2end/test_service_impl.h
index 052543a03e..e36423d44e 100644
--- a/test/cpp/end2end/test_service_impl.h
+++ b/test/cpp/end2end/test_service_impl.h
@@ -22,6 +22,7 @@
#include <mutex>
#include <grpc/grpc.h>
+#include <grpcpp/alarm.h>
#include <grpcpp/server_context.h>
#include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -35,6 +36,8 @@ const char* const kServerTryCancelRequest = "server_try_cancel";
const char* const kDebugInfoTrailerKey = "debug-info-bin";
const char* const kServerFinishAfterNReads = "server_finish_after_n_reads";
const char* const kServerUseCoalescingApi = "server_use_coalescing_api";
+const char* const kCheckClientInitialMetadataKey = "custom_client_metadata";
+const char* const kCheckClientInitialMetadataVal = "Value for client metadata";
typedef enum {
DO_NOT_CANCEL = 0,
@@ -52,6 +55,10 @@ class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
Status Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) override;
+ Status CheckClientInitialMetadata(ServerContext* context,
+ const SimpleRequest* request,
+ SimpleResponse* response) override;
+
// Unimplemented is left unimplemented to test the returned error.
Status RequestStream(ServerContext* context,
@@ -71,14 +78,48 @@ class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
}
private:
- int GetIntValueFromMetadata(
- const char* key,
- const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
- int default_value);
+ bool signal_client_;
+ std::mutex mu_;
+ std::unique_ptr<grpc::string> host_;
+};
+
+class CallbackTestServiceImpl
+ : public ::grpc::testing::EchoTestService::ExperimentalCallbackService {
+ public:
+ CallbackTestServiceImpl() : signal_client_(false), host_() {}
+ explicit CallbackTestServiceImpl(const grpc::string& host)
+ : signal_client_(false), host_(new grpc::string(host)) {}
+
+ void Echo(ServerContext* context, const EchoRequest* request,
+ EchoResponse* response,
+ experimental::ServerCallbackRpcController* controller) override;
+
+ void CheckClientInitialMetadata(
+ ServerContext* context, const SimpleRequest* request,
+ SimpleResponse* response,
+ experimental::ServerCallbackRpcController* controller) override;
- void ServerTryCancel(ServerContext* context);
+ experimental::ServerReadReactor<EchoRequest, EchoResponse>* RequestStream()
+ override;
+
+ experimental::ServerWriteReactor<EchoRequest, EchoResponse>* ResponseStream()
+ override;
+
+ experimental::ServerBidiReactor<EchoRequest, EchoResponse>* BidiStream()
+ override;
+
+ // Unimplemented is left unimplemented to test the returned error.
+ bool signal_client() {
+ std::unique_lock<std::mutex> lock(mu_);
+ return signal_client_;
+ }
private:
+ void EchoNonDelayed(ServerContext* context, const EchoRequest* request,
+ EchoResponse* response,
+ experimental::ServerCallbackRpcController* controller);
+
+ Alarm alarm_;
bool signal_client_;
std::mutex mu_;
std::unique_ptr<grpc::string> host_;
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 1a5ed28a2c..e30ce0dbcb 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -429,7 +429,7 @@ TYPED_TEST(AsyncClientEnd2endTest, ThreadStress) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc b/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc
index 664504a090..7339402830 100644
--- a/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc
+++ b/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc
@@ -370,7 +370,7 @@ TEST_F(StatsPluginEnd2EndTest, RequestReceivedMessagesPerRpc) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index eada2f671f..7dee85cc98 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -19,10 +19,12 @@
#ifndef GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
#define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
+#include <functional>
#include <memory>
#include <unordered_map>
#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
#include "src/core/lib/surface/call_test_only.h"
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index a99cf8122f..4ff153f980 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -76,7 +76,7 @@ void UnaryCompressionChecks(const InteropClientContextInspector& inspector,
InteropClient::ServiceStub::ServiceStub(
ChannelCreationFunc channel_creation_func, bool new_stub_every_call)
- : channel_creation_func_(channel_creation_func),
+ : channel_creation_func_(std::move(channel_creation_func)),
channel_(channel_creation_func_()),
new_stub_every_call_(new_stub_every_call) {
// If new_stub_every_call is false, then this is our chance to initialize
@@ -112,7 +112,7 @@ void InteropClient::ServiceStub::ResetChannel() {
InteropClient::InteropClient(ChannelCreationFunc channel_creation_func,
bool new_stub_every_test_case,
bool do_not_abort_on_transient_failures)
- : serviceStub_(channel_creation_func, new_stub_every_test_case),
+ : serviceStub_(std::move(channel_creation_func), new_stub_every_test_case),
do_not_abort_on_transient_failures_(do_not_abort_on_transient_failures) {}
bool InteropClient::AssertStatusOk(const Status& s,
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 7dc1956f78..5bbe913365 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -73,7 +73,7 @@ StressTestInteropClient::StressTestInteropClient(
long sleep_duration_ms, bool do_not_abort_on_transient_failures)
: test_id_(test_id),
server_address_(server_address),
- channel_creation_func_(channel_creation_func),
+ channel_creation_func_(std::move(channel_creation_func)),
interop_client_(new InteropClient(channel_creation_func_, false,
do_not_abort_on_transient_failures)),
test_selector_(test_selector),
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 1f7831096c..8d12606434 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -135,7 +135,8 @@ static void BM_LameChannelCallCreateCpp(benchmark::State& state) {
"",
grpc_lame_client_channel_create("localhost:1234",
GRPC_STATUS_UNAUTHENTICATED, "blah"),
- nullptr));
+ std::vector<std::unique_ptr<
+ grpc::experimental::ClientInterceptorFactoryInterface>>()));
grpc::CompletionQueue cq;
grpc::testing::EchoRequest send_request;
grpc::testing::EchoResponse recv_response;
@@ -468,7 +469,7 @@ class NoOp {
class SendEmptyMetadata {
public:
- SendEmptyMetadata() {
+ SendEmptyMetadata() : op_payload_(nullptr) {
memset(&op_, 0, sizeof(op_));
op_.on_complete = GRPC_CLOSURE_INIT(&closure_, DoNothing, nullptr,
grpc_schedule_on_exec_ctx);
diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
index ba4b57ad22..85d233dd26 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -778,8 +778,7 @@ static void free_timeout(void* p) { gpr_free(p); }
// Benchmark the current on_initial_header implementation
static void OnInitialHeader(void* user_data, grpc_mdelem md) {
// Setup for benchmark. This will bloat the absolute values of this benchmark
- grpc_chttp2_incoming_metadata_buffer buffer;
- grpc_chttp2_incoming_metadata_buffer_init(&buffer, (gpr_arena*)user_data);
+ grpc_chttp2_incoming_metadata_buffer buffer((gpr_arena*)user_data);
bool seen_error = false;
// Below here is the code we actually care about benchmarking
@@ -822,7 +821,6 @@ static void OnInitialHeader(void* user_data, grpc_mdelem md) {
GPR_ASSERT(0);
}
}
- grpc_chttp2_incoming_metadata_buffer_destroy(&buffer);
}
// Benchmark timeout handling
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index 189923a841..650152ecc0 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -54,7 +54,8 @@ class DummyEndpoint : public grpc_endpoint {
destroy,
get_resource_user,
get_peer,
- get_fd};
+ get_fd,
+ can_track_err};
grpc_endpoint::vtable = &my_vtable;
ru_ = grpc_resource_user_create(Library::get().rq(), "dummy_endpoint");
}
@@ -125,6 +126,7 @@ class DummyEndpoint : public grpc_endpoint {
}
static char* get_peer(grpc_endpoint* ep) { return gpr_strdup("test"); }
static int get_fd(grpc_endpoint* ep) { return 0; }
+ static bool can_track_err(grpc_endpoint* ep) { return false; }
};
class Fixture {
@@ -262,7 +264,7 @@ static void BM_StreamCreateDestroy(benchmark::State& state) {
Fixture f(grpc::ChannelArguments(), true);
Stream s(&f);
grpc_transport_stream_op_batch op;
- grpc_transport_stream_op_batch_payload op_payload;
+ grpc_transport_stream_op_batch_payload op_payload(nullptr);
memset(&op, 0, sizeof(op));
op.cancel_stream = true;
op.payload = &op_payload;
@@ -308,8 +310,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
Fixture f(grpc::ChannelArguments(), true);
Stream s(&f);
grpc_transport_stream_op_batch op;
- grpc_transport_stream_op_batch_payload op_payload;
- memset(&op_payload, 0, sizeof(op_payload));
+ grpc_transport_stream_op_batch_payload op_payload(nullptr);
std::unique_ptr<Closure> start;
std::unique_ptr<Closure> done;
@@ -360,8 +361,7 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
Stream s(&f);
s.Init(state);
grpc_transport_stream_op_batch op;
- grpc_transport_stream_op_batch_payload op_payload;
- memset(&op_payload, 0, sizeof(op_payload));
+ grpc_transport_stream_op_batch_payload op_payload(nullptr);
auto reset_op = [&]() {
memset(&op, 0, sizeof(op));
op.payload = &op_payload;
@@ -393,8 +393,7 @@ static void BM_TransportStreamSend(benchmark::State& state) {
auto s = std::unique_ptr<Stream>(new Stream(&f));
s->Init(state);
grpc_transport_stream_op_batch op;
- grpc_transport_stream_op_batch_payload op_payload;
- memset(&op_payload, 0, sizeof(op_payload));
+ grpc_transport_stream_op_batch_payload op_payload(nullptr);
auto reset_op = [&]() {
memset(&op, 0, sizeof(op));
op.payload = &op_payload;
@@ -526,8 +525,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
Fixture f(grpc::ChannelArguments(), true);
Stream s(&f);
s.Init(state);
- grpc_transport_stream_op_batch_payload op_payload;
- memset(&op_payload, 0, sizeof(op_payload));
+ grpc_transport_stream_op_batch_payload op_payload(nullptr);
grpc_transport_stream_op_batch op;
grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_stream;
grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384);
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 85767c8758..dca97c85b1 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -94,6 +94,7 @@ static const grpc_event_engine_vtable* init_engine_vtable(bool) {
g_vtable.pollset_destroy = pollset_destroy;
g_vtable.pollset_work = pollset_work;
g_vtable.pollset_kick = pollset_kick;
+ g_vtable.shutdown_background_closure = [] {};
g_vtable.shutdown_engine = [] {};
return &g_vtable;
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index e57eb6ddd1..6bbf553bbd 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -200,7 +200,7 @@ class EndpointPairFixture : public BaseFixture {
}
grpc_server_setup_transport(server_->c_server(), server_transport_,
- nullptr, server_args, 0);
+ nullptr, server_args, nullptr);
grpc_chttp2_transport_start_reading(server_transport_, nullptr, nullptr);
}
@@ -218,7 +218,10 @@ class EndpointPairFixture : public BaseFixture {
"target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport_);
grpc_chttp2_transport_start_reading(client_transport_, nullptr, nullptr);
- channel_ = CreateChannelInternal("", channel, nullptr);
+ channel_ = CreateChannelInternal(
+ "", channel,
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
}
diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc
index fc6721d0ba..3eb0e7d725 100644
--- a/test/cpp/naming/address_sorting_test.cc
+++ b/test/cpp/naming/address_sorting_test.cc
@@ -838,7 +838,7 @@ int main(int argc, char** argv) {
gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver);
}
gpr_free(resolver);
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
auto result = RUN_ALL_TESTS();
// Test sequential and nested inits and shutdowns.
diff --git a/test/cpp/naming/cancel_ares_query_test.cc b/test/cpp/naming/cancel_ares_query_test.cc
index dec7c171dc..3e789f0b14 100644
--- a/test/cpp/naming/cancel_ares_query_test.cc
+++ b/test/cpp/naming/cancel_ares_query_test.cc
@@ -260,8 +260,15 @@ TEST(CancelDuringAresQuery, TestFdsAreDeletedFromPollsetSet) {
grpc_pollset_set_destroy(fake_other_pollset_set);
}
-TEST(CancelDuringAresQuery,
- TestHitDeadlineAndDestroyChannelDuringAresResolutionIsGraceful) {
+// Settings for TestCancelDuringActiveQuery test
+typedef enum {
+ NONE,
+ SHORT,
+ ZERO,
+} cancellation_test_query_timeout_setting;
+
+void TestCancelDuringActiveQuery(
+ cancellation_test_query_timeout_setting query_timeout_setting) {
// Start up fake non responsive DNS server
int fake_dns_port = grpc_pick_unused_port_or_die();
FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port);
@@ -271,9 +278,33 @@ TEST(CancelDuringAresQuery,
&client_target,
"dns://[::1]:%d/dont-care-since-wont-be-resolved.test.com:1234",
fake_dns_port));
+ gpr_log(GPR_DEBUG, "TestCancelActiveDNSQuery. query timeout setting: %d",
+ query_timeout_setting);
+ grpc_channel_args* client_args = nullptr;
+ grpc_status_code expected_status_code = GRPC_STATUS_OK;
+ if (query_timeout_setting == NONE) {
+ expected_status_code = GRPC_STATUS_DEADLINE_EXCEEDED;
+ client_args = nullptr;
+ } else if (query_timeout_setting == SHORT) {
+ expected_status_code = GRPC_STATUS_UNAVAILABLE;
+ grpc_arg arg;
+ arg.type = GRPC_ARG_INTEGER;
+ arg.key = const_cast<char*>(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
+ arg.value.integer =
+ 1; // Set this shorter than the call deadline so that it goes off.
+ client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
+ } else if (query_timeout_setting == ZERO) {
+ expected_status_code = GRPC_STATUS_DEADLINE_EXCEEDED;
+ grpc_arg arg;
+ arg.type = GRPC_ARG_INTEGER;
+ arg.key = const_cast<char*>(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
+ arg.value.integer = 0; // Set this to zero to disable query timeouts.
+ client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
+ } else {
+ abort();
+ }
grpc_channel* client =
- grpc_insecure_channel_create(client_target,
- /* client_args */ nullptr, nullptr);
+ grpc_insecure_channel_create(client_target, client_args, nullptr);
gpr_free(client_target);
grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
cq_verifier* cqv = cq_verifier_create(cq);
@@ -325,8 +356,9 @@ TEST(CancelDuringAresQuery,
EXPECT_EQ(GRPC_CALL_OK, error);
CQ_EXPECT_COMPLETION(cqv, Tag(1), 1);
cq_verify(cqv);
- EXPECT_EQ(status, GRPC_STATUS_DEADLINE_EXCEEDED);
+ EXPECT_EQ(status, expected_status_code);
// Teardown
+ grpc_channel_args_destroy(client_args);
grpc_slice_unref(details);
gpr_free((void*)error_string);
grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -338,10 +370,27 @@ TEST(CancelDuringAresQuery,
EndTest(client, cq);
}
+TEST(CancelDuringAresQuery,
+ TestHitDeadlineAndDestroyChannelDuringAresResolutionIsGraceful) {
+ TestCancelDuringActiveQuery(NONE /* don't set query timeouts */);
+}
+
+TEST(
+ CancelDuringAresQuery,
+ TestHitDeadlineAndDestroyChannelDuringAresResolutionWithQueryTimeoutIsGraceful) {
+ TestCancelDuringActiveQuery(SHORT /* set short query timeout */);
+}
+
+TEST(
+ CancelDuringAresQuery,
+ TestHitDeadlineAndDestroyChannelDuringAresResolutionWithZeroQueryTimeoutIsGraceful) {
+ TestCancelDuringActiveQuery(ZERO /* disable query timeouts */);
+}
+
} // namespace
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
gpr_setenv("GRPC_DNS_RESOLVER", "ares");
// Sanity check the time that it takes to run the test
diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc
index 3dc6e7178c..fe6fcb8d9c 100644
--- a/test/cpp/naming/resolver_component_test.cc
+++ b/test/cpp/naming/resolver_component_test.cc
@@ -477,7 +477,7 @@ TEST(ResolverComponentTest, TestResolvesRelevantRecordsWithConcurrentFdStress) {
int main(int argc, char** argv) {
grpc_init();
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_target_name == "") {
diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc
index 32eab1fc44..7b22f23cf0 100644
--- a/test/cpp/performance/writes_per_rpc_test.cc
+++ b/test/cpp/performance/writes_per_rpc_test.cc
@@ -100,7 +100,7 @@ class EndpointPairFixture {
}
grpc_server_setup_transport(server_->c_server(), transport, nullptr,
- server_args, 0);
+ server_args, nullptr);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
@@ -118,7 +118,10 @@ class EndpointPairFixture {
"target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
- channel_ = CreateChannelInternal("", channel, nullptr);
+ channel_ = CreateChannelInternal(
+ "", channel,
+ std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>());
}
}
@@ -252,7 +255,7 @@ TEST(WritesPerRpcTest, UnaryPingPong) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD
index 2ef7441371..626ac5f3f2 100644
--- a/test/cpp/qps/BUILD
+++ b/test/cpp/qps/BUILD
@@ -36,6 +36,7 @@ grpc_cc_library(
"qps_server_builder.cc",
"qps_worker.cc",
"server_async.cc",
+ "server_callback.cc",
"server_sync.cc",
],
hdrs = [
@@ -169,7 +170,7 @@ grpc_cc_test(
grpc_cc_test(
name = "qps_openloop_test",
srcs = ["qps_openloop_test.cc"],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
+ exec_compatible_with = ["//third_party/toolchains/machine_size:large"],
deps = [
":benchmark_config",
":driver_impl",
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 4ed34e0405..668d941916 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -94,9 +94,11 @@ class ClientRequestCreator<ByteBuffer> {
public:
ClientRequestCreator(ByteBuffer* req, const PayloadConfig& payload_config) {
if (payload_config.has_bytebuf_params()) {
- std::unique_ptr<char[]> buf(
- new char[payload_config.bytebuf_params().req_size()]);
- Slice slice(buf.get(), payload_config.bytebuf_params().req_size());
+ size_t req_sz =
+ static_cast<size_t>(payload_config.bytebuf_params().req_size());
+ std::unique_ptr<char[]> buf(new char[req_sz]);
+ memset(buf.get(), 0, req_sz);
+ Slice slice(buf.get(), req_sz);
*req = ByteBuffer(&slice, 1);
} else {
GPR_ASSERT(false); // not appropriate for this specialization
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 11cfb4aa05..181e11f12b 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -95,6 +95,17 @@ static deque<string> get_workers(const string& env_name) {
return out;
}
+std::string GetCredType(
+ const std::string& worker_addr,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ const std::string& credential_type) {
+ auto it = per_worker_credential_types.find(worker_addr);
+ if (it != per_worker_credential_types.end()) {
+ return it->second;
+ }
+ return credential_type;
+}
+
// helpers for postprocess_scenario_result
static double WallTime(const ClientStats& s) { return s.time_elapsed(); }
static double SystemTime(const ClientStats& s) { return s.time_system(); }
@@ -198,8 +209,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
const ServerConfig& initial_server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
- const grpc::string& credential_type, bool run_inproc,
- int32_t median_latency_collection_interval_millis) {
+ const grpc::string& credential_type,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool run_inproc, int32_t median_latency_collection_interval_millis) {
if (run_inproc) {
g_inproc_servers = new std::vector<grpc::testing::Server*>;
}
@@ -278,7 +290,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
if (!run_inproc) {
servers[i].stub = WorkerService::NewStub(CreateChannel(
workers[i], GetCredentialsProvider()->GetChannelCredentials(
- credential_type, &channel_args)));
+ GetCredType(workers[i], per_worker_credential_types,
+ credential_type),
+ &channel_args)));
} else {
servers[i].stub = WorkerService::NewStub(
local_workers[i]->InProcessChannel(channel_args));
@@ -335,9 +349,11 @@ std::unique_ptr<ScenarioResult> RunScenario(
gpr_log(GPR_INFO, "Starting client on %s (worker #%" PRIuPTR ")",
worker.c_str(), i + num_servers);
if (!run_inproc) {
- clients[i].stub = WorkerService::NewStub(
- CreateChannel(worker, GetCredentialsProvider()->GetChannelCredentials(
- credential_type, &channel_args)));
+ clients[i].stub = WorkerService::NewStub(CreateChannel(
+ worker,
+ GetCredentialsProvider()->GetChannelCredentials(
+ GetCredType(worker, per_worker_credential_types, credential_type),
+ &channel_args)));
} else {
clients[i].stub = WorkerService::NewStub(
local_workers[i + num_servers]->InProcessChannel(channel_args));
@@ -529,7 +545,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
return result;
}
-bool RunQuit(const grpc::string& credential_type) {
+bool RunQuit(
+ const grpc::string& credential_type,
+ const std::map<std::string, std::string>& per_worker_credential_types) {
// Get client, server lists
bool result = true;
auto workers = get_workers("QPS_WORKERS");
@@ -541,7 +559,9 @@ bool RunQuit(const grpc::string& credential_type) {
for (size_t i = 0; i < workers.size(); i++) {
auto stub = WorkerService::NewStub(CreateChannel(
workers[i], GetCredentialsProvider()->GetChannelCredentials(
- credential_type, &channel_args)));
+ GetCredType(workers[i], per_worker_credential_types,
+ credential_type),
+ &channel_args)));
Void dummy;
grpc::ClientContext ctx;
ctx.set_wait_for_ready(true);
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index cda89f7ddf..568871d2da 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -32,10 +32,13 @@ std::unique_ptr<ScenarioResult> RunScenario(
const grpc::testing::ServerConfig& server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
- const grpc::string& credential_type, bool run_inproc,
- int32_t median_latency_collection_interval_millis);
+ const grpc::string& credential_type,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool run_inproc, int32_t median_latency_collection_interval_millis);
-bool RunQuit(const grpc::string& credential_type);
+bool RunQuit(
+ const grpc::string& credential_type,
+ const std::map<std::string, std::string>& per_worker_credential_types);
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
index 56d1730252..6257e42ebf 100644
--- a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
@@ -48,7 +48,7 @@ static void RunSynchronousUnaryPingPong() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, true, 0);
+ kInsecureCredentialsType, {}, true, 0);
GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc
index eaa0dd992c..1d67e79b86 100644
--- a/test/cpp/qps/qps_json_driver.cc
+++ b/test/cpp/qps/qps_json_driver.cc
@@ -65,6 +65,16 @@ DEFINE_string(json_file_out, "", "File to write the JSON output to.");
DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType,
"Credential type for communication with workers");
+DEFINE_string(
+ per_worker_credential_types, "",
+ "A map of QPS worker addresses to credential types. When creating a "
+ "channel to a QPS worker's driver port, the qps_json_driver first checks "
+ "if the 'name:port' string is in the map, and it uses the corresponding "
+ "credential type if so. If the QPS worker's 'name:port' string is not "
+ "in the map, then the driver -> worker channel will be created with "
+ "the credentials specified in --credential_type. The value of this flag "
+ "is a semicolon-separated list of map entries, where each map entry is "
+ "a comma-separated pair.");
DEFINE_bool(run_inproc, false, "Perform an in-process transport test");
DEFINE_int32(
median_latency_collection_interval_millis, 0,
@@ -75,16 +85,53 @@ DEFINE_int32(
namespace grpc {
namespace testing {
-static std::unique_ptr<ScenarioResult> RunAndReport(const Scenario& scenario,
- bool* success) {
+static std::map<std::string, std::string>
+ConstructPerWorkerCredentialTypesMap() {
+ // Parse a list of the form: "addr1,cred_type1;addr2,cred_type2;..." into
+ // a map.
+ std::string remaining = FLAGS_per_worker_credential_types;
+ std::map<std::string, std::string> out;
+ while (!remaining.empty()) {
+ size_t next_semicolon = remaining.find(';');
+ std::string next_entry = remaining.substr(0, next_semicolon);
+ if (next_semicolon == std::string::npos) {
+ remaining = "";
+ } else {
+ remaining = remaining.substr(next_semicolon + 1, std::string::npos);
+ }
+ size_t comma = next_entry.find(',');
+ if (comma == std::string::npos) {
+ gpr_log(GPR_ERROR,
+ "Expectd --per_worker_credential_types to be a list "
+ "of the form: 'addr1,cred_type1;addr2,cred_type2;...' "
+ "into.");
+ abort();
+ }
+ std::string addr = next_entry.substr(0, comma);
+ std::string cred_type = next_entry.substr(comma + 1, std::string::npos);
+ if (out.find(addr) != out.end()) {
+ gpr_log(GPR_ERROR,
+ "Found duplicate addr in per_worker_credential_types.");
+ abort();
+ }
+ out[addr] = cred_type;
+ }
+ return out;
+}
+
+static std::unique_ptr<ScenarioResult> RunAndReport(
+ const Scenario& scenario,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool* success) {
std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
- auto result = RunScenario(
- scenario.client_config(), scenario.num_clients(),
- scenario.server_config(), scenario.num_servers(),
- scenario.warmup_seconds(), scenario.benchmark_seconds(),
- !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
- FLAGS_qps_server_target_override, FLAGS_credential_type, FLAGS_run_inproc,
- FLAGS_median_latency_collection_interval_millis);
+ auto result =
+ RunScenario(scenario.client_config(), scenario.num_clients(),
+ scenario.server_config(), scenario.num_servers(),
+ scenario.warmup_seconds(), scenario.benchmark_seconds(),
+ !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
+ FLAGS_qps_server_target_override, FLAGS_credential_type,
+ per_worker_credential_types, FLAGS_run_inproc,
+ FLAGS_median_latency_collection_interval_millis);
// Amend the result with scenario config. Eventually we should adjust
// RunScenario contract so we don't need to touch the result here.
@@ -115,21 +162,26 @@ static std::unique_ptr<ScenarioResult> RunAndReport(const Scenario& scenario,
return result;
}
-static double GetCpuLoad(Scenario* scenario, double offered_load,
- bool* success) {
+static double GetCpuLoad(
+ Scenario* scenario, double offered_load,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool* success) {
scenario->mutable_client_config()
->mutable_load_params()
->mutable_poisson()
->set_offered_load(offered_load);
- auto result = RunAndReport(*scenario, success);
+ auto result = RunAndReport(*scenario, per_worker_credential_types, success);
return result->summary().server_cpu_usage();
}
-static double BinarySearch(Scenario* scenario, double targeted_cpu_load,
- double low, double high, bool* success) {
+static double BinarySearch(
+ Scenario* scenario, double targeted_cpu_load, double low, double high,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool* success) {
while (low <= high * (1 - FLAGS_error_tolerance)) {
double mid = low + (high - low) / 2;
- double current_cpu_load = GetCpuLoad(scenario, mid, success);
+ double current_cpu_load =
+ GetCpuLoad(scenario, mid, per_worker_credential_types, success);
gpr_log(GPR_DEBUG, "Binary Search: current_offered_load %.0f", mid);
if (!*success) {
gpr_log(GPR_ERROR, "Client/Server Failure");
@@ -145,12 +197,14 @@ static double BinarySearch(Scenario* scenario, double targeted_cpu_load,
return low;
}
-static double SearchOfferedLoad(double initial_offered_load,
- double targeted_cpu_load, Scenario* scenario,
- bool* success) {
+static double SearchOfferedLoad(
+ double initial_offered_load, double targeted_cpu_load, Scenario* scenario,
+ const std::map<std::string, std::string>& per_worker_credential_types,
+ bool* success) {
std::cerr << "RUNNING SCENARIO: " << scenario->name() << "\n";
double current_offered_load = initial_offered_load;
- double current_cpu_load = GetCpuLoad(scenario, current_offered_load, success);
+ double current_cpu_load = GetCpuLoad(scenario, current_offered_load,
+ per_worker_credential_types, success);
if (current_cpu_load > targeted_cpu_load) {
gpr_log(GPR_ERROR, "Initial offered load too high");
return -1;
@@ -158,14 +212,15 @@ static double SearchOfferedLoad(double initial_offered_load,
while (*success && (current_cpu_load < targeted_cpu_load)) {
current_offered_load *= 2;
- current_cpu_load = GetCpuLoad(scenario, current_offered_load, success);
+ current_cpu_load = GetCpuLoad(scenario, current_offered_load,
+ per_worker_credential_types, success);
gpr_log(GPR_DEBUG, "Binary Search: current_offered_load %.0f",
current_offered_load);
}
double targeted_offered_load =
BinarySearch(scenario, targeted_cpu_load, current_offered_load / 2,
- current_offered_load, success);
+ current_offered_load, per_worker_credential_types, success);
return targeted_offered_load;
}
@@ -183,6 +238,7 @@ static bool QpsDriver() {
abort();
}
+ auto per_worker_credential_types = ConstructPerWorkerCredentialTypesMap();
if (scfile) {
// Read the json data from disk
FILE* json_file = fopen(FLAGS_scenarios_file.c_str(), "r");
@@ -198,7 +254,7 @@ static bool QpsDriver() {
} else if (scjson) {
json = FLAGS_scenarios_json.c_str();
} else if (FLAGS_quit) {
- return RunQuit(FLAGS_credential_type);
+ return RunQuit(FLAGS_credential_type, per_worker_credential_types);
}
// Parse into an array of scenarios
@@ -212,15 +268,16 @@ static bool QpsDriver() {
for (int i = 0; i < scenarios.scenarios_size(); i++) {
if (FLAGS_search_param == "") {
const Scenario& scenario = scenarios.scenarios(i);
- RunAndReport(scenario, &success);
+ RunAndReport(scenario, per_worker_credential_types, &success);
} else {
if (FLAGS_search_param == "offered_load") {
Scenario* scenario = scenarios.mutable_scenarios(i);
- double targeted_offered_load =
- SearchOfferedLoad(FLAGS_initial_search_value,
- FLAGS_targeted_cpu_load, scenario, &success);
+ double targeted_offered_load = SearchOfferedLoad(
+ FLAGS_initial_search_value, FLAGS_targeted_cpu_load, scenario,
+ per_worker_credential_types, &success);
gpr_log(GPR_INFO, "targeted_offered_load %f", targeted_offered_load);
- GetCpuLoad(scenario, targeted_offered_load, &success);
+ GetCpuLoad(scenario, targeted_offered_load, per_worker_credential_types,
+ &success);
} else {
gpr_log(GPR_ERROR, "Unimplemented search param");
}
diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc
index 6044f4265a..68062e66f2 100644
--- a/test/cpp/qps/qps_openloop_test.cc
+++ b/test/cpp/qps/qps_openloop_test.cc
@@ -52,7 +52,7 @@ static void RunQPS() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, false, 0);
+ kInsecureCredentialsType, {}, false, 0);
GetReporter()->ReportQPSPerCore(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index d97d95d8f3..23fe72316a 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -79,6 +79,8 @@ static std::unique_ptr<Server> CreateServer(const ServerConfig& config) {
return CreateAsyncServer(config);
case ServerType::ASYNC_GENERIC_SERVER:
return CreateAsyncGenericServer(config);
+ case ServerType::CALLBACK_SERVER:
+ return CreateCallbackServer(config);
default:
abort();
}
diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
index a559c82cc8..422bd617eb 100644
--- a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
@@ -55,7 +55,7 @@ static void RunSynchronousUnaryPingPong() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, false, 0);
+ kInsecureCredentialsType, {}, false, 0);
GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 6b1ef93617..89b0e3af4b 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -152,6 +152,7 @@ class Server {
std::unique_ptr<Server> CreateSynchronousServer(const ServerConfig& config);
std::unique_ptr<Server> CreateAsyncServer(const ServerConfig& config);
std::unique_ptr<Server> CreateAsyncGenericServer(const ServerConfig& config);
+std::unique_ptr<Server> CreateCallbackServer(const ServerConfig& config);
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 5cd975cf74..a5f8347c26 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -562,6 +562,7 @@ static Status ProcessGenericRPC(const PayloadConfig& payload_config,
request->Clear();
int resp_size = payload_config.bytebuf_params().resp_size();
std::unique_ptr<char[]> buf(new char[resp_size]);
+ memset(buf.get(), 0, static_cast<size_t>(resp_size));
Slice slice(buf.get(), resp_size);
*response = ByteBuffer(&slice, 1);
return Status::OK;
diff --git a/test/cpp/qps/server_callback.cc b/test/cpp/qps/server_callback.cc
new file mode 100644
index 0000000000..8bedd44739
--- /dev/null
+++ b/test/cpp/qps/server_callback.cc
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_context.h>
+
+#include "src/core/lib/gpr/host_port.h"
+#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
+#include "test/cpp/qps/qps_server_builder.h"
+#include "test/cpp/qps/server.h"
+#include "test/cpp/qps/usage_timer.h"
+
+namespace grpc {
+namespace testing {
+
+class BenchmarkCallbackServiceImpl final
+ : public BenchmarkService::ExperimentalCallbackService {
+ public:
+ void UnaryCall(
+ ServerContext* context, const SimpleRequest* request,
+ SimpleResponse* response,
+ experimental::ServerCallbackRpcController* controller) override {
+ auto s = SetResponse(request, response);
+ controller->Finish(s);
+ }
+
+ private:
+ static Status SetResponse(const SimpleRequest* request,
+ SimpleResponse* response) {
+ if (request->response_size() > 0) {
+ if (!Server::SetPayload(request->response_type(),
+ request->response_size(),
+ response->mutable_payload())) {
+ return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
+ }
+ }
+ return Status::OK;
+ }
+};
+
+class CallbackServer final : public grpc::testing::Server {
+ public:
+ explicit CallbackServer(const ServerConfig& config) : Server(config) {
+ std::unique_ptr<ServerBuilder> builder = CreateQpsServerBuilder();
+
+ auto port_num = port();
+ // Negative port number means inproc server, so no listen port needed
+ if (port_num >= 0) {
+ char* server_address = nullptr;
+ gpr_join_host_port(&server_address, "::", port_num);
+ builder->AddListeningPort(server_address,
+ Server::CreateServerCredentials(config));
+ gpr_free(server_address);
+ }
+
+ ApplyConfigToBuilder(config, builder.get());
+
+ builder->RegisterService(&service_);
+
+ impl_ = builder->BuildAndStart();
+ }
+
+ std::shared_ptr<Channel> InProcessChannel(
+ const ChannelArguments& args) override {
+ return impl_->InProcessChannel(args);
+ }
+
+ private:
+ BenchmarkCallbackServiceImpl service_;
+ std::unique_ptr<grpc::Server> impl_;
+};
+
+std::unique_ptr<grpc::testing::Server> CreateCallbackServer(
+ const ServerConfig& config) {
+ return std::unique_ptr<Server>(new CallbackServer(config));
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/server/load_reporter/get_cpu_stats_test.cc b/test/cpp/server/load_reporter/get_cpu_stats_test.cc
index 5b1d5fa3a4..98c15b2c69 100644
--- a/test/cpp/server/load_reporter/get_cpu_stats_test.cc
+++ b/test/cpp/server/load_reporter/get_cpu_stats_test.cc
@@ -55,7 +55,7 @@ TEST(GetCpuStatsTest, Ascending) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/server/load_reporter/load_data_store_test.cc b/test/cpp/server/load_reporter/load_data_store_test.cc
index c92c407e4f..a3a67a2851 100644
--- a/test/cpp/server/load_reporter/load_data_store_test.cc
+++ b/test/cpp/server/load_reporter/load_data_store_test.cc
@@ -475,7 +475,7 @@ TEST_F(PerBalancerStoreTest, DataAggregation) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/server/load_reporter/load_reporter_test.cc b/test/cpp/server/load_reporter/load_reporter_test.cc
index 0d56cdf431..9d2ebfb0b4 100644
--- a/test/cpp/server/load_reporter/load_reporter_test.cc
+++ b/test/cpp/server/load_reporter/load_reporter_test.cc
@@ -501,7 +501,7 @@ TEST_F(LoadReportTest, BasicReport) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index c8d4333ef0..61e65029ff 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -181,16 +181,19 @@ grpc_cc_test(
data = [
"//src/proto/grpc/testing:echo.proto",
"//src/proto/grpc/testing:echo_messages.proto",
+ "//src/proto/grpc/testing:simple_messages.proto",
],
external_deps = [
"gtest",
],
+ tags = ["nomsan"], # death tests seem to be incompatible with msan
deps = [
":grpc_cli_libs",
":test_util",
"//:grpc++_reflection",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing:simple_messages_proto",
"//test/core/end2end:ssl_test_data",
"//test/core/util:grpc_test_util",
],
diff --git a/test/cpp/util/byte_buffer_proto_helper.h b/test/cpp/util/byte_buffer_proto_helper.h
index eb923eccb5..3d01fb2468 100644
--- a/test/cpp/util/byte_buffer_proto_helper.h
+++ b/test/cpp/util/byte_buffer_proto_helper.h
@@ -27,12 +27,13 @@
namespace grpc {
namespace testing {
-bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message);
+bool ParseFromByteBuffer(ByteBuffer* buffer,
+ ::grpc::protobuf::Message* message);
std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
- grpc::protobuf::Message* message);
+ ::grpc::protobuf::Message* message);
-bool SerializeToByteBufferInPlace(grpc::protobuf::Message* message,
+bool SerializeToByteBufferInPlace(::grpc::protobuf::Message* message,
ByteBuffer* buffer);
} // namespace testing
diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc
index 42a436d49b..ff9d887385 100644
--- a/test/cpp/util/channel_trace_proto_helper.cc
+++ b/test/cpp/util/channel_trace_proto_helper.cc
@@ -82,6 +82,11 @@ void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str) {
json_c_str);
}
+void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetServerResponse>(
+ json_c_str);
+}
+
void ValidateSubchannelProtoJsonTranslation(char* json_c_str) {
VaidateProtoJsonTranslation<grpc::channelz::v1::Subchannel>(json_c_str);
}
diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h
index 67c363e89b..4f74e02f10 100644
--- a/test/cpp/util/channel_trace_proto_helper.h
+++ b/test/cpp/util/channel_trace_proto_helper.h
@@ -26,6 +26,7 @@ void ValidateChannelTraceProtoJsonTranslation(char* json_c_str);
void ValidateChannelProtoJsonTranslation(char* json_c_str);
void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str);
void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str);
+void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str);
void ValidateSubchannelProtoJsonTranslation(char* json_c_str);
void ValidateServerProtoJsonTranslation(char* json_c_str);
void ValidateGetServersResponseProtoJsonTranslation(char* json_c_str);
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index 516f3fa53d..1d641535e2 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -122,7 +122,7 @@ TEST_F(CliCallTest, SimpleRpc) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
index be9a624a2c..b96b00f2db 100644
--- a/test/cpp/util/grpc_tool_test.cc
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -48,6 +48,7 @@ using grpc::testing::EchoResponse;
#define ECHO_TEST_SERVICE_SUMMARY \
"Echo\n" \
+ "CheckClientInitialMetadata\n" \
"RequestStream\n" \
"ResponseStream\n" \
"BidiStream\n" \
@@ -59,6 +60,8 @@ using grpc::testing::EchoResponse;
"service EchoTestService {\n" \
" rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
"{}\n" \
+ " rpc CheckClientInitialMetadata(grpc.testing.SimpleRequest) returns " \
+ "(grpc.testing.SimpleResponse) {}\n" \
" rpc RequestStream(stream grpc.testing.EchoRequest) returns " \
"(grpc.testing.EchoResponse) {}\n" \
" rpc ResponseStream(grpc.testing.EchoRequest) returns (stream " \
@@ -1173,7 +1176,7 @@ TEST_F(GrpcToolTest, ListCommand_OverrideSslHostName) {
} // namespace grpc
int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
return RUN_ALL_TESTS();
diff --git a/third_party/boringssl-with-bazel b/third_party/boringssl-with-bazel
-Subproject 8149b351bf797bd80e063787886b7618f508e45
+Subproject afc30d43eef92979b05776ec0963c9cede5fb80
diff --git a/third_party/data-plane-api b/third_party/data-plane-api
new file mode 160000
+Subproject 911001cdca003337bdb93fab32740cde61bafee
diff --git a/third_party/googleapis b/third_party/googleapis
new file mode 160000
+Subproject 80ed4d0bbf65d57cc267dfc63bd2584557f11f9
diff --git a/third_party/protoc-gen-validate b/third_party/protoc-gen-validate
new file mode 160000
+Subproject e143189bf6f37b3957fb31743df6a1bcf4a8c68
diff --git a/third_party/toolchains/BUILD b/third_party/toolchains/BUILD
index 02cd87a7b9..e213461acc 100644
--- a/third_party/toolchains/BUILD
+++ b/third_party/toolchains/BUILD
@@ -16,37 +16,72 @@ licenses(["notice"]) # Apache v2
package(default_visibility = ["//visibility:public"])
-exports_files(["RBE_USE_MACHINE_TYPE_LARGE",])
-
# Latest RBE Ubuntu16_04 container
# Update every time when a new container is released.
alias(
name = "rbe_ubuntu1604",
- actual = ":rbe_ubuntu1604_r328903",
+ actual = ":rbe_ubuntu1604_r342117",
+)
+
+alias(
+ name = "rbe_ubuntu1604_large",
+ actual = ":rbe_ubuntu1604_r342117_large",
)
-# RBE Ubuntu16_04 r328903
+# RBE Ubuntu16_04 r342117
platform(
- name = "rbe_ubuntu1604_r328903",
+ name = "rbe_ubuntu1604_r342117",
constraint_values = [
"@bazel_tools//platforms:x86_64",
"@bazel_tools//platforms:linux",
"@bazel_tools//tools/cpp:clang",
"@com_github_bazelbuild_bazeltoolchains//constraints:xenial",
"@com_github_bazelbuild_bazeltoolchains//constraints/sanitizers:support_msan",
+ "//third_party/toolchains/machine_size:standard",
],
remote_execution_properties = """
properties: {
name: "container-image"
- value:"docker://gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:59bf0e191a6b5cc1ab62c2224c810681d1326bad5a27b1d36c9f40113e79da7f"
+ value:"docker://gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:f3120a030a19d67626ababdac79cc787e699a1aa924081431285118f87e7b375"
}
properties: {
name: "gceMachineType" # Small machines for majority of tests.
value: "n1-highmem-2"
}
+ """,
+)
+
+# RBE Ubuntu16_04 r342117 large
+platform(
+ name = "rbe_ubuntu1604_r342117_large",
+ constraint_values = [
+ "@bazel_tools//platforms:x86_64",
+ "@bazel_tools//platforms:linux",
+ "@bazel_tools//tools/cpp:clang",
+ "@com_github_bazelbuild_bazeltoolchains//constraints:xenial",
+ "@com_github_bazelbuild_bazeltoolchains//constraints/sanitizers:support_msan",
+ "//third_party/toolchains/machine_size:large",
+ ],
+ remote_execution_properties = """
+ properties: {
+ name: "container-image"
+ value:"docker://gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:f3120a030a19d67626ababdac79cc787e699a1aa924081431285118f87e7b375"
+ }
properties: {
- name: "gceMachineType_LARGE" # Large machines for a small set of resource-consuming tests such as combiner_tests under TSAN.
+ name: "gceMachineType" # Large machines for some resource demanding tests (TSAN).
value: "n1-standard-8"
}
- """,
+ """,
+)
+
+# This target is auto-generated from release/cpp.tpl and should not be
+# modified directly.
+toolchain(
+ name = "cc-toolchain-clang-x86_64-default",
+ exec_compatible_with = [
+ ],
+ target_compatible_with = [
+ ],
+ toolchain = "@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.1/bazel_0.16.1/default:cc-compiler-k8",
+ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
diff --git a/third_party/toolchains/RBE_USE_MACHINE_TYPE_LARGE b/third_party/toolchains/RBE_USE_MACHINE_TYPE_LARGE
deleted file mode 100644
index b1120238d7..0000000000
--- a/third_party/toolchains/RBE_USE_MACHINE_TYPE_LARGE
+++ /dev/null
@@ -1 +0,0 @@
-# This file is a sentinel and is meant to be empty.
diff --git a/third_party/toolchains/machine_size/BUILD b/third_party/toolchains/machine_size/BUILD
new file mode 100644
index 0000000000..cc962946c3
--- /dev/null
+++ b/third_party/toolchains/machine_size/BUILD
@@ -0,0 +1,31 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"]) # Apache v2
+
+package(default_visibility = ["//visibility:public"])
+
+constraint_setting(name = "machine_size")
+
+constraint_value(
+ name = "large",
+ constraint_setting = ":machine_size",
+)
+
+constraint_value(
+ name = "standard",
+ constraint_setting = ":machine_size",
+)
+
+# Add other constraint values as needed (tiny, huge, etc.) in the future.
diff --git a/third_party/upb b/third_party/upb
new file mode 160000
+Subproject 9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e
diff --git a/tools/bazel.rc b/tools/bazel.rc
index 088c9da63c..59e597b472 100644
--- a/tools/bazel.rc
+++ b/tools/bazel.rc
@@ -6,28 +6,30 @@
build --client_env=CC=clang
build --copt=-DGRPC_BAZEL_BUILD
+build:opt --compilation_mode=opt
build:opt --copt=-Wframe-larger-than=16384
+build:dbg --compilation_mode=dbg
+
build:asan --strip=never
build:asan --copt=-fsanitize=address
build:asan --copt=-O0
build:asan --copt=-fno-omit-frame-pointer
build:asan --copt=-DGPR_NO_DIRECT_SYSCALLS
+build:asan --copt=-DADDRESS_SANITIZER # used by absl
build:asan --linkopt=-fsanitize=address
build:asan --action_env=ASAN_OPTIONS=detect_leaks=1:color=always
build:asan --action_env=LSAN_OPTIONS=suppressions=test/core/util/lsan_suppressions.txt:report_objects=1
build:msan --strip=never
-build:msan --copt=-fsanitize-coverage=edge
build:msan --copt=-fsanitize=memory
build:msan --copt=-O0
build:msan --copt=-fsanitize-memory-track-origins
build:msan --copt=-fsanitize-memory-use-after-dtor
build:msan --copt=-fno-omit-frame-pointer
-build:msan --copt=-fPIE
build:msan --copt=-DGPR_NO_DIRECT_SYSCALLS
+build:msan --copt=-DMEMORY_SANITIZER # used by absl
build:msan --linkopt=-fsanitize=memory
-build:msan --linkopt=-fPIE
build:msan --action_env=MSAN_OPTIONS=poison_in_dtor=1
build:tsan --strip=never
@@ -35,6 +37,8 @@ build:tsan --copt=-fsanitize=thread
build:tsan --copt=-fno-omit-frame-pointer
build:tsan --copt=-DGPR_NO_DIRECT_SYSCALLS
build:tsan --copt=-DGRPC_TSAN
+# TODO(jtattermusch): ideally we would set --copt=-DTHREAD_SANITIZER (used by absl)
+# but it seems to do more harm than good and triggers #17175
build:tsan --linkopt=-fsanitize=thread
build:tsan --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
@@ -43,6 +47,7 @@ build:ubsan --copt=-fsanitize=undefined
build:ubsan --copt=-fno-omit-frame-pointer
build:ubsan --copt=-DGRPC_UBSAN
build:ubsan --copt=-DNDEBUG
+build:ubsan --copt=-DUNDEFINED_BEHAVIOR_SANITIZER # used by absl
build:ubsan --copt=-fno-sanitize=function,vptr
build:ubsan --linkopt=-fsanitize=undefined
build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1:suppressions=test/core/util/ubsan_suppressions.txt
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index adfd4a24f9..ab288a0090 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -64,6 +64,7 @@ CONFIG = [
# well known method names
'/grpc.lb.v1.LoadBalancer/BalanceLoad',
'/grpc.health.v1.Health/Watch',
+ '/envoy.service.discovery.v2.AggregatedDiscoveryService/StreamAggregatedResources',
# compression algorithm names
'deflate',
'gzip',
diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh
index 82a818cce5..d17eb9fdb8 100755
--- a/tools/distrib/pylint_code.sh
+++ b/tools/distrib/pylint_code.sh
@@ -20,6 +20,7 @@ cd "$(dirname "$0")/../.."
DIRS=(
'src/python/grpcio/grpc'
+ 'src/python/grpcio_channelz/grpc_channelz'
'src/python/grpcio_health_checking/grpc_health'
'src/python/grpcio_reflection/grpc_reflection'
'src/python/grpcio_testing/grpc_testing'
diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py
index 732d948bbc..de47c00618 100755
--- a/tools/distrib/python/docgen.py
+++ b/tools/distrib/python/docgen.py
@@ -32,12 +32,10 @@ parser.add_argument(
help='GRPC/GPR libraries build configuration',
default='opt')
parser.add_argument('--submit', action='store_true')
-parser.add_argument('--gh-user', type=str, help='GitHub user to push as.')
parser.add_argument(
- '--gh-repo-owner',
+ '--repo-owner',
type=str,
- help=('Owner of the GitHub repository to be pushed; '
- 'defaults to --gh-user.'))
+ help=('Owner of the GitHub repository to be pushed'))
parser.add_argument('--doc-branch', type=str)
args = parser.parse_args()
@@ -70,7 +68,7 @@ subprocess_arguments_list = [
'env': environment
},
{
- 'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==10.0.1'],
+ 'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==18.1'],
'env': environment
},
{
@@ -78,7 +76,7 @@ subprocess_arguments_list = [
'env': environment
},
{
- 'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'build'],
+ 'args': [VIRTUALENV_PIP_PATH, 'install', 'Sphinx~=1.8.1'],
'env': environment
},
{
@@ -91,12 +89,12 @@ for subprocess_arguments in subprocess_arguments_list:
print('Running command: {}'.format(subprocess_arguments['args']))
subprocess.check_call(**subprocess_arguments)
-if args.submit:
- assert args.gh_user
+if not args.submit:
+ print('Please check generated Python doc inside doc/build')
+elif args.submit:
+ assert args.repo_owner
assert args.doc_branch
- github_user = args.gh_user
- github_repository_owner = (args.gh_repo_owner
- if args.gh_repo_owner else args.gh_user)
+ github_repository_owner = args.repo_owner
# Create a temporary directory out of tree, checkout gh-pages from the
# specified repository, edit it, and push it. It's up to the user to then go
# onto GitHub and make a PR against grpc/grpc:gh-pages.
@@ -109,16 +107,19 @@ if args.submit:
print('Cloning your repository...')
subprocess.check_call(
[
- 'git', 'clone', 'https://{}@github.com/{}/grpc'.format(
- github_user, github_repository_owner)
+ 'git',
+ 'clone',
+ '--branch',
+ 'gh-pages',
+ 'https://github.com/grpc/grpc',
],
cwd=repo_parent_dir)
+ subprocess.check_call(['git', 'checkout', '-b', doc_branch], cwd=repo_dir)
subprocess.check_call(
- ['git', 'remote', 'add', 'upstream', 'https://github.com/grpc/grpc'],
- cwd=repo_dir)
- subprocess.check_call(['git', 'fetch', 'upstream'], cwd=repo_dir)
- subprocess.check_call(
- ['git', 'checkout', 'upstream/gh-pages', '-b', doc_branch],
+ [
+ 'git', 'remote', 'add', 'ssh-origin',
+ 'git@github.com:%s/grpc.git' % (github_repository_owner)
+ ],
cwd=repo_dir)
print('Updating documentation...')
shutil.rmtree(python_doc_dir, ignore_errors=True)
@@ -130,7 +131,7 @@ if args.submit:
['git', 'commit', '-m', 'Auto-update Python documentation'],
cwd=repo_dir)
subprocess.check_call(
- ['git', 'push', '--set-upstream', 'origin', doc_branch],
+ ['git', 'push', '--set-upstream', 'ssh-origin', doc_branch],
cwd=repo_dir)
except subprocess.CalledProcessError:
print('Failed to push documentation. Examine this directory and push '
diff --git a/tools/distrib/python/grpcio_tools/MANIFEST.in b/tools/distrib/python/grpcio_tools/MANIFEST.in
index 11ce367747..4943751879 100644
--- a/tools/distrib/python/grpcio_tools/MANIFEST.in
+++ b/tools/distrib/python/grpcio_tools/MANIFEST.in
@@ -1,3 +1,4 @@
+include _parallel_compile_patch.py
include grpc_version.py
include protoc_deps.py
include protoc_lib_deps.py
diff --git a/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py
new file mode 100644
index 0000000000..4d03ef49ba
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py
@@ -0,0 +1,63 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Patches the compile() to allow enable parallel compilation of C/C++.
+
+build_ext has lots of C/C++ files and normally them one by one.
+Enabling parallel build helps a lot.
+"""
+
+import distutils.ccompiler
+import os
+
+try:
+ BUILD_EXT_COMPILER_JOBS = int(
+ os.environ.get('GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS', '1'))
+except ValueError:
+ BUILD_EXT_COMPILER_JOBS = 1
+
+
+# monkey-patch for parallel compilation
+def _parallel_compile(self,
+ sources,
+ output_dir=None,
+ macros=None,
+ include_dirs=None,
+ debug=0,
+ extra_preargs=None,
+ extra_postargs=None,
+ depends=None):
+ # setup the same way as distutils.ccompiler.CCompiler
+ # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564
+ macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
+ output_dir, macros, include_dirs, sources, depends, extra_postargs)
+ cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
+
+ def _compile_single_file(obj):
+ try:
+ src, ext = build[obj]
+ except KeyError:
+ return
+ self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
+
+ # run compilation of individual files in parallel
+ import multiprocessing.pool
+ multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map(
+ _compile_single_file, objects)
+ return objects
+
+
+def monkeypatch_compile_maybe():
+ """Monkeypatching is dumb, but the build speed gain is worth it."""
+ if BUILD_EXT_COMPILER_JOBS > 1:
+ distutils.ccompiler.CCompiler.compile = _parallel_compile
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 4b775e667e..29b2127960 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
-VERSION = '1.17.0.dev0'
+VERSION = '1.18.0.dev0'
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index c13dfe9ade..64c468cbf7 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -34,9 +34,12 @@ from setuptools.command import build_ext
os.chdir(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.abspath('.'))
+import _parallel_compile_patch
import protoc_lib_deps
import grpc_version
+_parallel_compile_patch.monkeypatch_compile_maybe()
+
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python',
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index b2216c79d4..b49fa10410 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM debian:jessie
+FROM debian:stretch
# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
@@ -67,37 +67,36 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
#================
# C# dependencies
-# Update to a newer version of mono
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian jessie main" | tee /etc/apt/sources.list.d/mono-official.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+# cmake >=3.6 needed to build grpc_csharp_ext
+RUN apt-get update && apt-get install -y cmake && apt-get clean
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
+# Install mono
+RUN apt-get update && apt-get install -y apt-transport-https dirmngr && apt-get clean
+RUN apt-key adv --no-tty --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb https://download.mono-project.com/repo/debian stable-stretch main" | tee /etc/apt/sources.list.d/mono-official-stable.list
+RUN apt-get update && apt-get install -y \
mono-devel \
ca-certificates-mono \
nuget \
&& apt-get clean
-RUN nuget update -self
+# Install dotnet SDK
+ENV DOTNET_SDK_VERSION 2.1.500
+RUN curl -sSL -o dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz \
+ && mkdir -p /usr/share/dotnet \
+ && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
+ && rm dotnet.tar.gz \
+ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
-#=================
-# Use cmake 3.6 from jessie-backports
-# needed to build grpc_csharp_ext with cmake
-RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+RUN curl -sSL -o dotnet_old.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/1.1.10/dotnet-debian.9-x64.1.1.10.tar.gz \
+ && mkdir -p dotnet_old \
+ && tar zxf dotnet_old.tar.gz -C dotnet_old \
+ && cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/ \
+ && rm -rf dotnet_old/ dotnet_old.tar.gz
+RUN apt-get update && apt-get install -y libunwind8 && apt-get clean
-# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
-RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003131
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
-RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
-# dotnet-dev-1.0.1
-RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
-RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
-RUN ln -s /opt/dotnet/dotnet /usr/local/bin
# Trigger the population of the local package cache
ENV NUGET_XMLDOC_MODE skip
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index b2216c79d4..b49fa10410 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM debian:jessie
+FROM debian:stretch
# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
@@ -67,37 +67,36 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
#================
# C# dependencies
-# Update to a newer version of mono
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian jessie main" | tee /etc/apt/sources.list.d/mono-official.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+# cmake >=3.6 needed to build grpc_csharp_ext
+RUN apt-get update && apt-get install -y cmake && apt-get clean
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
+# Install mono
+RUN apt-get update && apt-get install -y apt-transport-https dirmngr && apt-get clean
+RUN apt-key adv --no-tty --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb https://download.mono-project.com/repo/debian stable-stretch main" | tee /etc/apt/sources.list.d/mono-official-stable.list
+RUN apt-get update && apt-get install -y \
mono-devel \
ca-certificates-mono \
nuget \
&& apt-get clean
-RUN nuget update -self
+# Install dotnet SDK
+ENV DOTNET_SDK_VERSION 2.1.500
+RUN curl -sSL -o dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz \
+ && mkdir -p /usr/share/dotnet \
+ && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
+ && rm dotnet.tar.gz \
+ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
-#=================
-# Use cmake 3.6 from jessie-backports
-# needed to build grpc_csharp_ext with cmake
-RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+RUN curl -sSL -o dotnet_old.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/1.1.10/dotnet-debian.9-x64.1.1.10.tar.gz \
+ && mkdir -p dotnet_old \
+ && tar zxf dotnet_old.tar.gz -C dotnet_old \
+ && cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/ \
+ && rm -rf dotnet_old/ dotnet_old.tar.gz
+RUN apt-get update && apt-get install -y libunwind8 && apt-get clean
-# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
-RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003131
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
-RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
-# dotnet-dev-1.0.1
-RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
-RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
-RUN ln -s /opt/dotnet/dotnet /usr/local/bin
# Trigger the population of the local package cache
ENV NUGET_XMLDOC_MODE skip
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
index fd549fb9e5..8b8c6be8f1 100755
--- a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
@@ -28,10 +28,10 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-make install-certs
+make install-certs -j4
# build C++ interop client & server
-make interop_client interop_server -j2
+make interop_client interop_server -j4
# build C++ http2 client
-make http2_client
+make http2_client -j4
diff --git a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
index 999976d15d..fc5c22083a 100755
--- a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
@@ -28,12 +28,13 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-# gRPC core and protobuf need to be installed
-make install
+# Install gRPC C core and build codegen plugins
+make -j4 install_c plugins
-(cd src/php/ext/grpc && phpize && ./configure && make)
+(cd src/php/ext/grpc && phpize && ./configure && make -j4)
-(cd third_party/protobuf && make install)
+# Install protobuf (need access to protoc)
+(cd third_party/protobuf && make -j4 install)
(cd src/php && php -d extension=ext/grpc/modules/grpc.so /usr/local/bin/composer install)
diff --git a/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
index efa97530c8..248a8f680b 100755
--- a/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
@@ -28,12 +28,13 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-# gRPC core and protobuf need to be installed
-make install
+# Install gRPC C core and build codegen plugins
+make -j4 install_c plugins
-(cd src/php/ext/grpc && phpize && ./configure && make)
+(cd src/php/ext/grpc && phpize && ./configure && make -j4)
-(cd third_party/protobuf && make install)
+# Install protobuf (need access to protoc)
+(cd third_party/protobuf && make -j4 install)
(cd src/php && php -d extension=ext/grpc/modules/grpc.so /usr/local/bin/composer install)
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index dadd856740..acad500f90 100644
--- a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM debian:jessie
-
+FROM debian:stretch
+
# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
@@ -49,27 +49,24 @@ RUN apt-get update && apt-get install -y \
# Build profiling
RUN apt-get update && apt-get install -y time && apt-get clean
-#====================
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
- python-all-dev \
- python3-all-dev \
- python-pip
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client oauth2client
-# Install Python packages from PyPI
-RUN pip install --upgrade pip==10.0.1
-RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
-# Install pip and virtualenv for Python 3.4
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
-RUN python3.4 -m pip install virtualenv
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]
+
+
+RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
index 7917e1cd60..468aa20e3f 100755
--- a/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
@@ -28,5 +28,5 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-# interop tests only run using python2.7 currently (and python build is slow)
-tools/run_tests/run_tests.py -l python --compiler python2.7 -c opt --build_only
+# interop tests only run using python3.7 currently (and python build is slow)
+tools/run_tests/run_tests.py -l python --compiler python3.7 -c opt --build_only
diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile
index 4f913dc396..0aa6209f4f 100644
--- a/tools/dockerfile/test/bazel/Dockerfile
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -44,9 +44,10 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
#========================
# Bazel installation
-RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
-RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
-RUN apt-get -y update && apt-get -y install bazel=0.15.0 && apt-get clean
+
+RUN apt-get update && apt-get install -y wget && apt-get clean
+RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
+RUN chmod 755 /usr/local/bin/bazel
RUN mkdir -p /var/local/jenkins
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_stretch_x64/Dockerfile
index 030d301a40..04d2584209 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_stretch_x64/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015 gRPC authors.
+# Copyright 2018 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM debian:jessie
+FROM debian:stretch
# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
@@ -71,37 +71,36 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
#================
# C# dependencies
-# Update to a newer version of mono
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian jessie main" | tee /etc/apt/sources.list.d/mono-official.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+# cmake >=3.6 needed to build grpc_csharp_ext
+RUN apt-get update && apt-get install -y cmake && apt-get clean
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
+# Install mono
+RUN apt-get update && apt-get install -y apt-transport-https dirmngr && apt-get clean
+RUN apt-key adv --no-tty --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb https://download.mono-project.com/repo/debian stable-stretch main" | tee /etc/apt/sources.list.d/mono-official-stable.list
+RUN apt-get update && apt-get install -y \
mono-devel \
ca-certificates-mono \
nuget \
&& apt-get clean
-RUN nuget update -self
+# Install dotnet SDK
+ENV DOTNET_SDK_VERSION 2.1.500
+RUN curl -sSL -o dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz \
+ && mkdir -p /usr/share/dotnet \
+ && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
+ && rm dotnet.tar.gz \
+ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
-#=================
-# Use cmake 3.6 from jessie-backports
-# needed to build grpc_csharp_ext with cmake
-RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+RUN curl -sSL -o dotnet_old.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/1.1.10/dotnet-debian.9-x64.1.1.10.tar.gz \
+ && mkdir -p dotnet_old \
+ && tar zxf dotnet_old.tar.gz -C dotnet_old \
+ && cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/ \
+ && rm -rf dotnet_old/ dotnet_old.tar.gz
+RUN apt-get update && apt-get install -y libunwind8 && apt-get clean
-# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
-RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003131
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
-RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
-# dotnet-dev-1.0.1
-RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
-RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
-RUN ln -s /opt/dotnet/dotnet /usr/local/bin
# Trigger the population of the local package cache
ENV NUGET_XMLDOC_MODE skip
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
deleted file mode 100644
index 3c95554b02..0000000000
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ /dev/null
@@ -1,170 +0,0 @@
-# Copyright 2016 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
- autoconf \
- autotools-dev \
- build-essential \
- bzip2 \
- ccache \
- curl \
- dnsutils \
- gcc \
- gcc-multilib \
- git \
- golang \
- gyp \
- lcov \
- libc6 \
- libc6-dbg \
- libc6-dev \
- libgtest-dev \
- libtool \
- make \
- perl \
- strace \
- python-dev \
- python-setuptools \
- python-yaml \
- telnet \
- unzip \
- wget \
- zip && apt-get clean
-
-#================
-# Build profiling
-RUN apt-get update && apt-get install -y time && apt-get clean
-
-# Google Cloud platform API libraries
-RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client oauth2client
-
-#================
-# C# dependencies
-
-# Update to a newer version of mono
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian jessie main" | tee /etc/apt/sources.list.d/mono-official.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
- mono-devel \
- ca-certificates-mono \
- nuget \
- && apt-get clean
-
-RUN nuget update -self
-
-#=================
-# Use cmake 3.6 from jessie-backports
-# needed to build grpc_csharp_ext with cmake
-
-RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
-
-# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
-RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003131
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
-RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
-# dotnet-dev-1.0.1
-RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
-RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
-RUN ln -s /opt/dotnet/dotnet /usr/local/bin
-
-# Trigger the population of the local package cache
-ENV NUGET_XMLDOC_MODE skip
-RUN mkdir warmup \
- && cd warmup \
- && dotnet new \
- && cd .. \
- && rm -rf warmup
-
-#=================
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
-
-#==================
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-# Install all versions of node that we want to test
-RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm install 10 && npm config set cache /tmp/npm-cache"
-RUN /bin/bash -l -c "nvm alias default 10"
-#=================
-# PHP dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
- git php5 php5-dev phpunit unzip
-
-#==================
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-#====================
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
- python-all-dev \
- python3-all-dev \
- python-pip
-
-# Install Python packages from PyPI
-RUN pip install --upgrade pip==10.0.1
-RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
-
-# Install pip and virtualenv for Python 3.4
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
-RUN python3.4 -m pip install virtualenv
-
-# Install coverage for Python test coverage reporting
-RUN pip install coverage
-ENV PATH ~/.local/bin:$PATH
-
-# Install Mako to generate files in grpc/grpc-node
-RUN pip install Mako
-
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/test/python_alpine_x64/Dockerfile b/tools/dockerfile/test/python_alpine_x64/Dockerfile
index 6e06e2d52c..3001bf43ff 100644
--- a/tools/dockerfile/test/python_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/python_alpine_x64/Dockerfile
@@ -42,13 +42,7 @@ RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
# Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client
-
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN pip install --upgrade google-api-python-client oauth2client
RUN mkdir -p /var/local/jenkins
diff --git a/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile b/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
index add1cc509d..45291ffdcf 100644
--- a/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
+++ b/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
@@ -70,3 +70,6 @@ CMD ["bash"]
RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
+
+# for Python test coverage reporting
+RUN pip install coverage
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 1abf6bddce..5c19711ee9 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.17.0-dev
+PROJECT_NUMBER = 1.18.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -777,6 +777,7 @@ doc/environment_variables.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
+doc/grpc_release_schedule.md \
doc/health-checking.md \
doc/http-grpc-status-mapping.md \
doc/http2-interop-test-descriptions.md \
@@ -943,6 +944,8 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/call_op_set.h \
+include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -957,7 +960,9 @@ include/grpcpp/impl/codegen/core_codegen.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/proto_buffer_reader.h \
@@ -967,7 +972,9 @@ include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -1003,6 +1010,7 @@ include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
+include/grpcpp/support/server_callback.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
include/grpcpp/support/status_code_enum.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 26e671668e..0e65bf6daa 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.17.0-dev
+PROJECT_NUMBER = 1.18.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -777,6 +777,7 @@ doc/environment_variables.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
+doc/grpc_release_schedule.md \
doc/health-checking.md \
doc/http-grpc-status-mapping.md \
doc/http2-interop-test-descriptions.md \
@@ -944,6 +945,8 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/call_op_set.h \
+include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
@@ -959,7 +962,9 @@ include/grpcpp/impl/codegen/core_codegen.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
+include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/proto_buffer_reader.h \
@@ -969,7 +974,9 @@ include/grpcpp/impl/codegen/rpc_method.h \
include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
+include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
+include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -1005,6 +1012,7 @@ include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
+include/grpcpp/support/server_callback.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
include/grpcpp/support/status_code_enum.h \
@@ -1076,6 +1084,7 @@ src/core/lib/iomgr/buffer_list.h \
src/core/lib/iomgr/call_combiner.h \
src/core/lib/iomgr/closure.h \
src/core/lib/iomgr/combiner.h \
+src/core/lib/iomgr/dynamic_annotations.h \
src/core/lib/iomgr/endpoint.h \
src/core/lib/iomgr/endpoint_pair.h \
src/core/lib/iomgr/error.h \
@@ -1176,9 +1185,11 @@ src/core/lib/transport/status_metadata.h \
src/core/lib/transport/timeout_encoding.h \
src/core/lib/transport/transport.h \
src/core/lib/transport/transport_impl.h \
+src/core/lib/uri/uri_parser.h \
src/cpp/README.md \
src/cpp/client/channel_cc.cc \
src/cpp/client/client_context.cc \
+src/cpp/client/client_interceptor.cc \
src/cpp/client/create_channel.cc \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_internal.h \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index b78fb607ad..8c557383b2 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -784,6 +784,7 @@ doc/environment_variables.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
+doc/grpc_release_schedule.md \
doc/health-checking.md \
doc/http-grpc-status-mapping.md \
doc/http2-interop-test-descriptions.md \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 437253c01b..dd5bead58c 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -784,6 +784,7 @@ doc/environment_variables.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
+doc/grpc_release_schedule.md \
doc/health-checking.md \
doc/http-grpc-status-mapping.md \
doc/http2-interop-test-descriptions.md \
@@ -926,8 +927,6 @@ src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_factory.h \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/lb_policy_registry.h \
-src/core/ext/filters/client_channel/method_params.cc \
-src/core/ext/filters/client_channel/method_params.h \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/parse_address.h \
src/core/ext/filters/client_channel/proxy_mapper.cc \
@@ -956,14 +955,14 @@ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.h \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/resolver_registry.h \
+src/core/ext/filters/client_channel/resolver_result_parsing.cc \
+src/core/ext/filters/client_channel/resolver_result_parsing.h \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/retry_throttle.h \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel.h \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/subchannel_index.h \
-src/core/ext/filters/client_channel/uri_parser.cc \
-src/core/ext/filters/client_channel/uri_parser.h \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/deadline/deadline_filter.h \
src/core/ext/filters/http/client/http_client_filter.cc \
@@ -1011,6 +1010,8 @@ src/core/ext/transport/chttp2/transport/bin_encoder.h \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.h \
+src/core/ext/transport/chttp2/transport/context_list.cc \
+src/core/ext/transport/chttp2/transport/context_list.h \
src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/flow_control.h \
src/core/ext/transport/chttp2/transport/frame.h \
@@ -1181,6 +1182,7 @@ src/core/lib/iomgr/call_combiner.h \
src/core/lib/iomgr/closure.h \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/combiner.h \
+src/core/lib/iomgr/dynamic_annotations.h \
src/core/lib/iomgr/endpoint.cc \
src/core/lib/iomgr/endpoint.h \
src/core/lib/iomgr/endpoint_pair.h \
@@ -1478,6 +1480,8 @@ src/core/lib/transport/transport.cc \
src/core/lib/transport/transport.h \
src/core/lib/transport/transport_impl.h \
src/core/lib/transport/transport_op_string.cc \
+src/core/lib/uri/uri_parser.cc \
+src/core/lib/uri/uri_parser.h \
src/core/plugin_registry/grpc_plugin_registry.cc \
src/core/tsi/README.md \
src/core/tsi/alts/crypt/aes_gcm.cc \
@@ -1501,8 +1505,8 @@ src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \
src/core/tsi/alts/handshaker/alts_handshaker_service_api.h \
src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \
src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h \
-src/core/tsi/alts/handshaker/alts_tsi_event.cc \
-src/core/tsi/alts/handshaker/alts_tsi_event.h \
+src/core/tsi/alts/handshaker/alts_shared_resource.cc \
+src/core/tsi/alts/handshaker/alts_shared_resource.h \
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
src/core/tsi/alts/handshaker/alts_tsi_handshaker.h \
src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h \
@@ -1527,8 +1531,6 @@ src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h \
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h \
-src/core/tsi/alts_transport_security.cc \
-src/core/tsi/alts_transport_security.h \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/fake_transport_security.h \
src/core/tsi/grpc_shadow_boringssl.h \
diff --git a/tools/gce/create_linux_kokoro_performance_worker_from_image.sh b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
index 0f7939be4c..28c49a66f2 100755
--- a/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
+++ b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
@@ -22,7 +22,7 @@ cd "$(dirname "$0")"
CLOUD_PROJECT=grpc-testing
ZONE=us-central1-b # this zone allows 32core machines
-LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v2 # update if newer image exists
+LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v3 # update if newer image exists
INSTANCE_NAME="${1:-grpc-kokoro-performance-server}"
MACHINE_TYPE="${2:-n1-standard-32}"
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
index b78695d802..d67ff58506 100755
--- a/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -133,6 +133,12 @@ sudo cp -r dotnet105_download/shared/Microsoft.NETCore.App/1.0.5/ /usr/share/dot
wget -q http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu55_55.1-7ubuntu0.4_amd64.deb
sudo dpkg -i libicu55_55.1-7ubuntu0.4_amd64.deb
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+wget -q -O dotnet_old.tar.gz https://download.visualstudio.microsoft.com/download/pr/b25b5650-0cb8-4699-a347-48d73650da0b/920966211e9bb1907232bbda1faa895a/dotnet-ubuntu.18.04-x64.1.1.10.tar.gz
+mkdir -p dotnet_old
+tar zxf dotnet_old.tar.gz -C dotnet_old
+sudo cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/
+
# Ruby dependencies
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable --ruby
diff --git a/tools/gcp/utils/big_query_utils.py b/tools/gcp/utils/big_query_utils.py
index 3e811ca2bf..6e9cda376b 100755
--- a/tools/gcp/utils/big_query_utils.py
+++ b/tools/gcp/utils/big_query_utils.py
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import print_function
+
import argparse
import json
import uuid
@@ -50,11 +52,11 @@ def create_dataset(biq_query, project_id, dataset_id):
dataset_req.execute(num_retries=NUM_RETRIES)
except HttpError as http_error:
if http_error.resp.status == 409:
- print 'Warning: The dataset %s already exists' % dataset_id
+ print('Warning: The dataset %s already exists' % dataset_id)
else:
# Note: For more debugging info, print "http_error.content"
- print 'Error in creating dataset: %s. Err: %s' % (dataset_id,
- http_error)
+ print('Error in creating dataset: %s. Err: %s' % (dataset_id,
+ http_error))
is_success = False
return is_success
@@ -122,13 +124,13 @@ def create_table2(big_query,
table_req = big_query.tables().insert(
projectId=project_id, datasetId=dataset_id, body=body)
res = table_req.execute(num_retries=NUM_RETRIES)
- print 'Successfully created %s "%s"' % (res['kind'], res['id'])
+ print('Successfully created %s "%s"' % (res['kind'], res['id']))
except HttpError as http_error:
if http_error.resp.status == 409:
- print 'Warning: Table %s already exists' % table_id
+ print('Warning: Table %s already exists' % table_id)
else:
- print 'Error in creating table: %s. Err: %s' % (table_id,
- http_error)
+ print('Error in creating table: %s. Err: %s' % (table_id,
+ http_error))
is_success = False
return is_success
@@ -154,9 +156,9 @@ def patch_table(big_query, project_id, dataset_id, table_id, fields_schema):
tableId=table_id,
body=body)
res = table_req.execute(num_retries=NUM_RETRIES)
- print 'Successfully patched %s "%s"' % (res['kind'], res['id'])
+ print('Successfully patched %s "%s"' % (res['kind'], res['id']))
except HttpError as http_error:
- print 'Error in creating table: %s. Err: %s' % (table_id, http_error)
+ print('Error in creating table: %s. Err: %s' % (table_id, http_error))
is_success = False
return is_success
@@ -172,10 +174,10 @@ def insert_rows(big_query, project_id, dataset_id, table_id, rows_list):
body=body)
res = insert_req.execute(num_retries=NUM_RETRIES)
if res.get('insertErrors', None):
- print 'Error inserting rows! Response: %s' % res
+ print('Error inserting rows! Response: %s' % res)
is_success = False
except HttpError as http_error:
- print 'Error inserting rows to the table %s' % table_id
+ print('Error inserting rows to the table %s' % table_id)
is_success = False
return is_success
@@ -189,8 +191,8 @@ def sync_query_job(big_query, project_id, query, timeout=5000):
projectId=project_id,
body=query_data).execute(num_retries=NUM_RETRIES)
except HttpError as http_error:
- print 'Query execute job failed with error: %s' % http_error
- print http_error.content
+ print('Query execute job failed with error: %s' % http_error)
+ print(http_error.content)
return query_job
diff --git a/tools/internal_ci/README.md b/tools/internal_ci/README.md
index e80e342dcd..af582c471e 100644
--- a/tools/internal_ci/README.md
+++ b/tools/internal_ci/README.md
@@ -1,6 +1,7 @@
-# Internal continuous integration
+# Kokoro CI job configurations and testing scripts
-gRPC's externally facing testing is managed by Jenkins CI (see `tools/jenkins`
-directory). Nevertheless, some of the tests are better suited for being run
-on internal infrastructure and using an internal CI system. Configuration for
-such tests is under this directory.
+gRPC uses a continous integration tool called "Kokoro" (a.k.a "internal CI")
+for running majority of its open source tests.
+This directory contains the external part of kokoro test job configurations
+(the actual job definitions live in an internal repository) and the shell
+scripts that act as entry points to exectute the actual tests.
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index 3212e80854..bafe0d98c1 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -15,14 +15,8 @@
# Source this rc script to prepare the environment for macos builds
-sudo launchctl limit maxfiles unlimited unlimited
-
-# show current maxfiles
+# show original open file limit values
launchctl limit maxfiles
-
-ulimit -n 10000
-
-# show current limits
ulimit -a
# synchronize the clock
@@ -34,15 +28,14 @@ sudo systemsetup -setusingnetworktime on
date
# Add GCP credentials for BQ access
-# pin google-api-python-client to avoid https://github.com/grpc/grpc/issues/15600
-pip install google-api-python-client==1.6.7 --user python
+pip install google-api-python-client oauth2client --user python
export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json
# If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then
set +x
brew update
- brew install jq
+ brew install jq || brew upgrade jq
ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref)
export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch"
@@ -57,25 +50,25 @@ source $HOME/.rvm/scripts/rvm
set -e # rvm commands are very verbose
time rvm install 2.5.0
rvm use 2.5.0 --default
-gem install bundler --no-ri --no-doc
-gem install cocoapods --version 1.3.1 --no-ri --no-doc
-gem install rake-compiler --no-ri --no-doc
+time gem install bundler --no-ri --no-doc
+time gem install cocoapods --version 1.3.1 --no-ri --no-doc
+time gem install rake-compiler --no-ri --no-doc
rvm osx-ssl-certs status all
rvm osx-ssl-certs update all
set -ex
# cocoapods
export LANG=en_US.UTF-8
-pod repo update # needed by python
+time pod repo update # needed by python
# python
-pip install virtualenv --user python
-pip install -U Mako six tox setuptools twisted pyyaml --user python
+time pip install virtualenv --user python
+time pip install -U Mako six tox setuptools twisted pyyaml --user python
export PYTHONPATH=/Library/Python/3.4/site-packages
# Install Python 3.7
-curl -O https://www.python.org/ftp/python/3.7.0/python-3.7.0-macosx10.9.pkg
-sudo installer -pkg ./python-3.7.0-macosx10.9.pkg -target /
+time curl -O https://www.python.org/ftp/python/3.7.0/python-3.7.0-macosx10.9.pkg
+time sudo installer -pkg ./python-3.7.0-macosx10.9.pkg -target /
# set xcode version for Obj-C tests
sudo xcode-select -switch /Applications/Xcode_9.2.app/Contents/Developer/
@@ -88,11 +81,15 @@ export DOTNET_CLI_TELEMETRY_OPTOUT=true
# TODO(jtattermusch): better debugging of clock skew, remove once not needed
date
-git submodule update --init
+time git submodule update --init
# Store intermediate build files of ObjC tests into /tmpfs
mkdir /tmpfs/Build-ios-binary-size
ln -s /tmpfs/Build-ios-binary-size src/objective-c/examples/Sample/Build
-mkdir /tmpfs/DerivedData
+mkdir -p /tmpfs/DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData
+mkdir -p ~/Library/Developer/Xcode
ln -s /tmpfs/DerivedData ~/Library/Developer/Xcode/DerivedData
+
+# PHP tests currently require using an older version of PHPUnit
+ln -sf /usr/local/bin/phpunit-5.7 /usr/local/bin/phpunit
diff --git a/tools/internal_ci/linux/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
index 24fbdf74c2..87ec60c7c0 100755
--- a/tools/internal_ci/linux/grpc_asan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
index 768e15b380..d35bbbd275 100755
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
@@ -15,31 +15,35 @@
set -ex
-# A temporary solution to give Kokoro credentials.
-# The file name 4321_grpc-testing-service needs to match auth_credential in
+# A temporary solution to give Kokoro credentials.
+# The file name 4321_grpc-testing-service needs to match auth_credential in
# the build config.
mkdir -p ${KOKORO_KEYSTORE_DIR}
cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-latest-release" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-latest-release"
+# Download bazel
+temp_dir="$(mktemp -d)"
+wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O "${temp_dir}/bazel"
+chmod 755 "${temp_dir}/bazel"
export PATH="${temp_dir}:${PATH}"
# This should show ${temp_dir}/bazel
which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
# change to grpc repo root
cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-export KOKORO_FOUNDRY_PROJECT_ID="projects/grpc-testing/instances/default_instance"
+# to get "bazel" link for kokoro build, we need to generate
+# invocation UUID, set a flag for bazel to use it
+# and upload "bazel_invocation_ids" file as artifact.
+BAZEL_INVOCATION_ID="$(uuidgen)"
+echo "${BAZEL_INVOCATION_ID}" >"${KOKORO_ARTIFACTS_DIR}/bazel_invocation_ids"
-# TODO(adelez): implement size for test targets and change test_timeout back
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
+bazel \
--bazelrc=tools/remote_build/kokoro.bazelrc \
test \
+ --invocation_id="${BAZEL_INVOCATION_ID}" \
$@ \
-- //test/... || FAILED="true"
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
index 51cb66f5b8..fdd5b2e4cd 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600 --cache_test_results=no"
+EXTRA_FLAGS="--config=dbg --test_timeout=300,450,1200,3600 --cache_test_results=no"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
index cbba9067ad..30b2b17a67 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600 --cache_test_results=no"
+EXTRA_FLAGS="--config=opt --test_timeout=300,450,1200,3600 --cache_test_results=no"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_coverage.sh b/tools/internal_ci/linux/grpc_coverage.sh
index 97166372ab..a91cffdf98 100755
--- a/tools/internal_ci/linux/grpc_coverage.sh
+++ b/tools/internal_ci/linux/grpc_coverage.sh
@@ -21,12 +21,20 @@ cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc
python tools/run_tests/run_tests.py \
- --use_docker \
- -t \
- -l all \
- -c gcov \
- -x sponge_log.xml \
- -j 16 || FAILED="true"
+ -l c c++ -x coverage_cpp/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l python -x coverage_python/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l ruby -x coverage_ruby/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l php -x coverage_php/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
# HTML reports can't be easily displayed in GCS, so create a zip archive
# and put it under reports directory to get it uploaded as an artifact.
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
index 3c9798d375..21f9d48ac4 100755
--- a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
+++ b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
@@ -21,7 +21,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
# "smoketest" scenarios on a single VM (=no remote VM for running qps_workers)
tools/run_tests/run_performance_tests.py \
- -l c++ csharp ruby java python go php7 php7_protobuf_c node node_purejs \
+ -l c++ csharp ruby java python go php7 php7_protobuf_c node \
--netperf \
--category smoketest \
-u kbuilder \
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.sh b/tools/internal_ci/linux/grpc_full_performance_master.sh
index 24ee71edd1..05a014b88a 100755
--- a/tools/internal_ci/linux/grpc_full_performance_master.sh
+++ b/tools/internal_ci/linux/grpc_full_performance_master.sh
@@ -21,7 +21,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
# run 8core client vs 8core server
tools/run_tests/run_performance_tests.py \
- -l c++ csharp ruby java python go php7 php7_protobuf_c node node_purejs \
+ -l c++ csharp ruby java python go php7 php7_protobuf_c node \
--netperf \
--category scalable \
--remote_worker_host grpc-kokoro-performance-server-8core grpc-kokoro-performance-client-8core grpc-kokoro-performance-client2-8core \
diff --git a/tools/internal_ci/linux/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
index 1ef13ef0d4..c7e4b1fa1a 100644
--- a/tools/internal_ci/linux/grpc_msan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
@@ -15,67 +15,5 @@
set -ex
-# A temporary solution to give Kokoro credentials.
-# The file name 4321_grpc-testing-service needs to match auth_credential in
-# the build config.
-# TODO: Use keystore.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-latest-release" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-latest-release"
-export PATH="${temp_dir}:${PATH}"
-# This should show ${temp_dir}/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-export KOKORO_FOUNDRY_PROJECT_ID="projects/grpc-testing/instances/default_instance"
-
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
- --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
- test --jobs="200" \
- --test_timeout="3600,3600,3600,3600" \
- --test_output=errors \
- --verbose_failures=true \
- --keep_going \
- --remote_accept_cached=true \
- --spawn_strategy=remote \
- --remote_local_fallback=false \
- --remote_timeout=3600 \
- --strategy=Javac=remote \
- --strategy=Closure=remote \
- --genrule_strategy=remote \
- --experimental_strict_action_env=true \
- --define GRPC_PORT_ISOLATED_RUNTIME=1 \
- --copt=-gmlt \
- --strip=never \
- --cxxopt=--stdlib=libc++ \
- --copt=-fsanitize=memory \
- --linkopt=-fsanitize=memory \
- --copt=-fsanitize-memory-track-origins \
- --action_env=LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH \
- --host_crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/default:toolchain \
- --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/msan:toolchain \
- --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
- --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/cpp:cc-toolchain-clang-x86_64-default \
- --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --host_platform=//third_party/toolchains:rbe_ubuntu1604 \
- --platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --test_env=GRPC_VERBOSITY=debug \
- --remote_instance_name=projects/grpc-testing/instances/default_instance \
- -- //test/... || FAILED="true"
-
-# Sleep to let ResultStore finish writing results before querying
-sleep 60
-python ./tools/run_tests/python_utils/upload_rbe_results.py
-
-if [ "$FAILED" != "" ]
-then
- exit 1
-fi
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
index 4f98d0a93a..156d65955a 100755
--- a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
+++ b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
@@ -24,4 +24,4 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
${name}')
cd /var/local/git/grpc/test
-bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/...
+bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/...
diff --git a/tools/internal_ci/linux/grpc_run_tests_matrix.sh b/tools/internal_ci/linux/grpc_run_tests_matrix.sh
index 4e7515227b..f9acd814ae 100755
--- a/tools/internal_ci/linux/grpc_run_tests_matrix.sh
+++ b/tools/internal_ci/linux/grpc_run_tests_matrix.sh
@@ -22,6 +22,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_rc
# If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ] && [ -n "$RUN_TESTS_FLAGS" ]; then
+ sudo apt-get update
sudo apt-get install -y jq
ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref)
export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch"
diff --git a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
index 7686794784..fcf3095d48 100644
--- a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
index 4350cb1ba5..f45be4d1c9 100644
--- a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
index 84b65a3eb1..00f92921de 100644
--- a/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
index 8e2aaebaee..f1e6588517 100644
--- a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600"
+set -ex
+
+EXTRA_FLAGS="--config=dbg --test_timeout=300,450,1200,3600"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
index ded0d368a5..77744de49f 100644
--- a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600"
+set -ex
+
+EXTRA_FLAGS="--config=opt --test_timeout=300,450,1200,3600"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/run_tests/helper_scripts/run_lcov.sh b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
index 9d8b6793fc..c85a837a44 100755..100644
--- a/tools/run_tests/helper_scripts/run_lcov.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright 2015 gRPC authors.
+#!/usr/bin/env bash
+# Copyright 2018 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,17 +15,4 @@
set -ex
-out=$(readlink -f "${1:-coverage}")
-
-root=$(readlink -f "$(dirname "$0")/../../..")
-shift || true
-tmp=$(mktemp)
-cd "$root"
-tools/run_tests/run_tests.py -c gcov -l c c++ "$@" || true
-lcov --capture --directory . --output-file "$tmp"
-genhtml "$tmp" --output-directory "$out"
-rm "$tmp"
-if which xdg-open > /dev/null
-then
- xdg-open "file://$out/index.html"
-fi
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan
diff --git a/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
index 4a9687f7e2..f3e98e63da 100644
--- a/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
@@ -13,4 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan
diff --git a/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
index fb69d73635..b94935eab1 100644
--- a/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
@@ -13,4 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan
diff --git a/tools/internal_ci/macos/grpc_basictests_dbg.cfg b/tools/internal_ci/macos/grpc_basictests_dbg.cfg
index e6f9c7ec87..1c7ed26d64 100644
--- a/tools/internal_ci/macos/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/macos/grpc_basictests_dbg.cfg
@@ -27,5 +27,5 @@ action {
env_vars {
key: "RUN_TESTS_FLAGS"
- value: "-f basictests macos dbg --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
+ value: "-f basictests macos dbg --exclude objc --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
}
diff --git a/tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg b/tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg
new file mode 100644
index 0000000000..068961234b
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg
@@ -0,0 +1,31 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc dbg --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
+}
diff --git a/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg b/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg
new file mode 100644
index 0000000000..927fa50deb
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg
@@ -0,0 +1,31 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc opt --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
+}
diff --git a/tools/internal_ci/macos/grpc_basictests_opt.cfg b/tools/internal_ci/macos/grpc_basictests_opt.cfg
index f2a83fe95a..f46ebaa786 100644
--- a/tools/internal_ci/macos/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/macos/grpc_basictests_opt.cfg
@@ -27,5 +27,5 @@ action {
env_vars {
key: "RUN_TESTS_FLAGS"
- value: "-f basictests macos opt --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
+ value: "-f basictests macos opt --exclude objc --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
}
diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg
index c759397b78..c91c033916 100644
--- a/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg
@@ -27,5 +27,5 @@ action {
env_vars {
key: "RUN_TESTS_FLAGS"
- value: "-f basictests macos dbg --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
+ value: "-f basictests macos dbg --exclude objc --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
}
diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg
new file mode 100644
index 0000000000..775fd355a5
--- /dev/null
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg
@@ -0,0 +1,31 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc dbg --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
+}
diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg
new file mode 100644
index 0000000000..652ef1bb77
--- /dev/null
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg
@@ -0,0 +1,31 @@
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc opt --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
+}
diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg
index 4d68341405..532234fa84 100644
--- a/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg
@@ -27,5 +27,5 @@ action {
env_vars {
key: "RUN_TESTS_FLAGS"
- value: "-f basictests macos opt --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
+ value: "-f basictests macos opt --exclude objc --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
}
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index c4935e8eee..ff3344cd95 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -204,6 +204,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.15.0': None
},
+ {
+ 'v1.16.1': None
+ },
],
'python': [
{
diff --git a/tools/remote_build/README.md b/tools/remote_build/README.md
index 7492de75a5..19739e9ee1 100644
--- a/tools/remote_build/README.md
+++ b/tools/remote_build/README.md
@@ -17,10 +17,10 @@ and tests run by Kokoro CI.
## Running remote build manually from dev workstation
-Run from repository root:
+Run from repository root (opt, dbg):
```
# manual run of bazel tests remotely on Foundry
-bazel --bazelrc=tools/remote_build/manual.bazelrc test -c opt //test/...
+bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=opt //test/...
```
Sanitizer runs (asan, msan, tsan, ubsan):
@@ -28,3 +28,6 @@ Sanitizer runs (asan, msan, tsan, ubsan):
# manual run of bazel tests remotely on Foundry with given sanitizer
bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/...
```
+
+Available command line options can be found in
+[Bazel command line reference](https://docs.bazel.build/versions/master/command-line-reference.html)
diff --git a/tools/remote_build/kokoro.bazelrc b/tools/remote_build/kokoro.bazelrc
index 0aacddf663..2fbdd3ce02 100644
--- a/tools/remote_build/kokoro.bazelrc
+++ b/tools/remote_build/kokoro.bazelrc
@@ -16,8 +16,22 @@
import %workspace%/tools/remote_build/rbe_common.bazelrc
+build --remote_cache=remotebuildexecution.googleapis.com
+build --remote_executor=remotebuildexecution.googleapis.com
+build --tls_enabled=true
+
+build --auth_enabled=true
+# magic location where kokoro script puts the credentials
+build --auth_credentials=/tmpfs/src/keystore/4321_grpc-testing-service
+build --auth_scope=https://www.googleapis.com/auth/cloud-source-tools
+
+build --bes_backend=buildeventservice.googleapis.com
+build --bes_timeout=600s
+build --project_id=grpc-testing
+
+# required by kokoro for some reason
+build --test_env=USER=anon
+
build --jobs=200
build --test_output=errors
-build --keep_going
-build --remote_accept_cached=true
-build --remote_local_fallback=true
+build --keep_going=true
diff --git a/tools/remote_build/manual.bazelrc b/tools/remote_build/manual.bazelrc
index d67bafedf3..b4fdc70637 100644
--- a/tools/remote_build/manual.bazelrc
+++ b/tools/remote_build/manual.bazelrc
@@ -40,3 +40,6 @@ build --jobs=100
# TODO(jtattermusch): this should be part of the common config
# but currently sanitizers use different test_timeout values
build --test_timeout=300,450,1200,3600
+
+# print output for tests that fail (default is "summary")
+build --test_output=errors
diff --git a/tools/remote_build/rbe_common.bazelrc b/tools/remote_build/rbe_common.bazelrc
index cdf492a2cc..aa3ddb050c 100644
--- a/tools/remote_build/rbe_common.bazelrc
+++ b/tools/remote_build/rbe_common.bazelrc
@@ -18,10 +18,10 @@
startup --host_jvm_args=-Dbazel.DigestFunction=SHA256
-build --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/default:toolchain
-build --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/cpp:cc-toolchain-clang-x86_64-default
+build --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.1/bazel_0.16.1/default:toolchain
+build --extra_toolchains=//third_party/toolchains:cc-toolchain-clang-x86_64-default
# Use custom execution platforms defined in third_party/toolchains
-build --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604
+build --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604,//third_party/toolchains:rbe_ubuntu1604_large
build --host_platform=//third_party/toolchains:rbe_ubuntu1604
build --platforms=//third_party/toolchains:rbe_ubuntu1604
@@ -48,40 +48,38 @@ test --test_env=GRPC_VERBOSITY=debug
build:asan --copt=-gmlt
# TODO(jtattermusch): use more reasonable test timeout
build:asan --test_timeout=3600
-build:asan --test_tag_filters=-qps_json_driver,-json_run_localhost
-# TODO: revisit these from bazel.rc:
-#build:asan --copt=-O0
-#build:asan --copt=-fno-omit-frame-pointer
-#build:asan --copt=-DGPR_NO_DIRECT_SYSCALLS
-#build:asan --action_env=ASAN_OPTIONS=detect_leaks=1:color=always
-#build:asan --action_env=LSAN_OPTIONS=suppressions=test/core/util/lsan_suppressions.txt:report_objects=1
+build:asan --test_tag_filters=-qps_json_driver
-# TODO(jtattermusch): align msan settings from tools/bazel.rc
-# and grpc_msan_on_foundry.sh
+# memory sanitizer: most settings are already in %workspace%/.bazelrc
+# we only need a few additional ones that are Foundry specific
+build:msan --copt=-gmlt
+# TODO(jtattermusch): use more reasonable test timeout
+build:msan --test_timeout=3600
+# TODO(jtattermusch): revisit the disabled tests
+build:msan --test_tag_filters=-nomsan,-json_run_localhost
+build:msan --cxxopt=--stdlib=libc++
+# setting LD_LIBRARY_PATH is necessary
+# to avoid "libc++.so.1: cannot open shared object file"
+build:msan --action_env=LD_LIBRARY_PATH=/usr/local/lib
+build:msan --host_crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.1/bazel_0.16.1/default:toolchain
+# override the config-agnostic crosstool_top
+build:msan --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.1/bazel_0.16.1/msan:toolchain
# thread sanitizer: most settings are already in %workspace%/.bazelrc
# we only need a few additional ones that are Foundry specific
build:tsan --copt=-gmlt
# TODO(jtattermusch): use more reasonable test timeout
build:tsan --test_timeout=3600
-build:tsan --test_tag_filters=-qps_json_driver,-json_run_localhost
-# TODO: revisit these from bazel.rc:
-#build:tsan --copt=-fno-omit-frame-pointer
-#build:tsan --copt=-DGPR_NO_DIRECT_SYSCALLS
-#build:tsan --copt=-DGRPC_TSAN
+build:tsan --test_tag_filters=-qps_json_driver
+build:tsan --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604,//third_party/toolchains:rbe_ubuntu1604_large
# undefined behavior sanitizer: most settings are already in %workspace%/.bazelrc
# we only need a few additional ones that are Foundry specific
build:ubsan --copt=-gmlt
# TODO(jtattermusch): use more reasonable test timeout
build:ubsan --test_timeout=3600
-# TODO: revisit these from bazel.rc:
-#build:ubsan --copt=-fno-omit-frame-pointer
-#build:ubsan --copt=-DGRPC_UBSAN
-#build:ubsan --copt=-DNDEBUG
-#build:ubsan --copt=-fno-sanitize=function,vptr
-# TODO: revisit this from grpc_ubsan_on_foundry.sh:
-#--crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.0/bazel_0.15.0/ubsan:toolchain
+# override the config-agnostic crosstool_top
+--crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.1/bazel_0.16.1/ubsan:toolchain
# TODO(jtattermusch): remove this once Foundry adds the env to the docker image.
# ubsan needs symbolizer to work properly, otherwise the suppression file doesn't work
# and we get test failures.
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index d18ea2aca1..aa1d0c3bf2 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -124,6 +124,8 @@ class PythonArtifact:
# https://github.com/resin-io-projects/armv7hf-debian-qemu/issues/9
# A QEMU bug causes submodule update to hang, so we copy directly
environ['RELATIVE_COPY_PATH'] = '.'
+ # Parallel builds are counterproductive in emulated environment
+ environ['GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS'] = '1'
extra_args = ' --entrypoint=/usr/bin/qemu-arm-static '
return create_docker_jobspec(
self.name,
diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
index d277668c94..795e80dc40 100644
--- a/tools/run_tests/artifacts/build_artifact_python.bat
+++ b/tools/run_tests/artifacts/build_artifact_python.bat
@@ -22,6 +22,10 @@ pip install -rrequirements.txt
set GRPC_PYTHON_BUILD_WITH_CYTHON=1
+@rem Allow build_ext to build C/C++ files in parallel
+@rem by enabling a monkeypatch. It speeds up the build a lot.
+set GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=2
+
mkdir -p %ARTIFACTS_OUT%
set ARTIFACT_DIR=%cd%\%ARTIFACTS_OUT%
diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
index 2878005bb2..605470325a 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -22,6 +22,11 @@ export PYTHON=${PYTHON:-python}
export PIP=${PIP:-pip}
export AUDITWHEEL=${AUDITWHEEL:-auditwheel}
+# Allow build_ext to build C/C++ files in parallel
+# by enabling a monkeypatch. It speeds up the build a lot.
+# Use externally provided GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS value if set.
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=${GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS:-2}
+
mkdir -p "${ARTIFACTS_OUT}"
ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}"
@@ -100,9 +105,15 @@ then
"${PIP}" install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/"
# Build grpcio_testing source distribution
- ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py sdist
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py preprocess \
+ sdist
cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR"
+ # Build grpcio_channelz source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_channelz/setup.py \
+ preprocess build_package_protos sdist
+ cp -r src/python/grpcio_channelz/dist/* "$ARTIFACT_DIR"
+
# Build grpcio_health_checking source distribution
${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \
preprocess build_package_protos sdist
diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
index d93e8979fc..29801a5b86 100755
--- a/tools/run_tests/artifacts/build_package_python.sh
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -19,20 +19,10 @@ cd "$(dirname "$0")/../../.."
mkdir -p artifacts/
+# All the python packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true
-strip_binary_wheel() {
- TEMP_WHEEL_DIR=$(mktemp -d)
- unzip "$1" -d "$TEMP_WHEEL_DIR"
- find "$TEMP_WHEEL_DIR" -name "_protoc_compiler*.so" -exec strip --strip-debug {} ";"
- find "$TEMP_WHEEL_DIR" -name "cygrpc*.so" -exec strip --strip-debug {} ";"
- (cd "$TEMP_WHEEL_DIR" && zip -r - .) > "$1"
-}
-
-for wheel in artifacts/*.whl; do
- strip_binary_wheel "$wheel"
-done
-
# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
# source distribution package, and only one of them will end up
# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/dockerize/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
index 614049cae5..1741b3268b 100755
--- a/tools/run_tests/dockerize/build_docker_and_run_tests.sh
+++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
@@ -22,9 +22,6 @@ cd "$(dirname "$0")/../../.."
git_root=$(pwd)
cd -
-# Ensure existence of ccache directory
-mkdir -p /tmp/ccache
-
# Inputs
# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
@@ -57,7 +54,6 @@ docker run \
-e "RUN_TESTS_COMMAND=$RUN_TESTS_COMMAND" \
-e "config=$config" \
-e "arch=$arch" \
- -e CCACHE_DIR=/tmp/ccache \
-e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
-e HOST_GIT_ROOT="$git_root" \
-e LOCAL_GIT_ROOT=$docker_instance_git_root \
@@ -73,7 +69,6 @@ docker run \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
-v ~/.config/gcloud:/root/.config/gcloud \
-v "$git_root:$docker_instance_git_root" \
- -v /tmp/ccache:/tmp/ccache \
-v /tmp/npm-cache:/tmp/npm-cache \
-w /var/local/git/grpc \
--name="$CONTAINER_NAME" \
diff --git a/tools/run_tests/dockerize/build_interop_image.sh b/tools/run_tests/dockerize/build_interop_image.sh
index fcfcdeb4e4..126dd4065e 100755
--- a/tools/run_tests/dockerize/build_interop_image.sh
+++ b/tools/run_tests/dockerize/build_interop_image.sh
@@ -64,8 +64,6 @@ else
echo "WARNING: grpc-node not found, it won't be mounted to the docker container."
fi
-mkdir -p /tmp/ccache
-
# Mount service account dir if available.
# If service_directory does not contain the service account JSON file,
# some of the tests will fail.
@@ -105,14 +103,12 @@ CONTAINER_NAME="build_${BASE_NAME}_$(uuidgen)"
# shellcheck disable=SC2086
(docker run \
--cap-add SYS_PTRACE \
- -e CCACHE_DIR=/tmp/ccache \
-e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
-e THIS_IS_REALLY_NEEDED_ONCE_AGAIN='For issue 4835. See https://github.com/docker/docker/issues/14203 for why docker is awful' \
-i \
$TTY_FLAG \
$MOUNT_ARGS \
$BUILD_INTEROP_DOCKER_EXTRA_ARGS \
- -v /tmp/ccache:/tmp/ccache \
--name="$CONTAINER_NAME" \
"$BASE_IMAGE" \
bash -l "/var/local/jenkins/grpc/tools/dockerfile/interoptest/$BASE_NAME/build_interop.sh" \
diff --git a/tools/run_tests/dockerize/docker_run_tests.sh b/tools/run_tests/dockerize/docker_run_tests.sh
index c41734c92d..b7686e48ba 100755
--- a/tools/run_tests/dockerize/docker_run_tests.sh
+++ b/tools/run_tests/dockerize/docker_run_tests.sh
@@ -38,16 +38,8 @@ exit_code=0
$RUN_TESTS_COMMAND || exit_code=$?
-cd reports
-echo '<html><head></head><body>' > index.html
-find . -maxdepth 1 -mindepth 1 -type d | sort | while read d ; do
- d=${d#*/}
- n=${d//_/ }
- echo "<a href='$d/index.html'>$n</a><br />" >> index.html
-done
-echo '</body></html>' >> index.html
-cd ..
-
+# The easiest way to copy all the reports files from inside of
+# the docker container is to zip them and then copy the zip.
zip -r reports.zip reports
find . -name report.xml -print0 | xargs -0 -r zip reports.zip
find . -name sponge_log.xml -print0 | xargs -0 -r zip reports.zip
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 3a442864e8..0a7a4daf7d 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -3394,6 +3394,29 @@
"grpc++_test_util",
"grpc_test_util"
],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "client_interceptors_end2end_test",
+ "src": [
+ "test/cpp/end2end/client_interceptors_end2end_test.cc",
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
"headers": [],
"is_filegroup": false,
"language": "c++",
@@ -3487,6 +3510,23 @@
{
"deps": [
"gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "context_list_test",
+ "src": [
+ "test/core/transport/chttp2/context_list_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
"grpc",
"grpc++"
],
@@ -3578,12 +3618,16 @@
"grpc++_test_util",
"grpc_test_util"
],
- "headers": [],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
"is_filegroup": false,
"language": "c++",
"name": "end2end_test",
"src": [
- "test/cpp/end2end/end2end_test.cc"
+ "test/cpp/end2end/end2end_test.cc",
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h"
],
"third_party": false,
"type": "target"
@@ -4702,6 +4746,29 @@
"deps": [
"gpr",
"gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "server_interceptors_end2end_test",
+ "src": [
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h",
+ "test/cpp/end2end/server_interceptors_end2end_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
"grpc++_test_util_unsecure",
"grpc++_unsecure",
"grpc_test_util_unsecure",
@@ -7377,6 +7444,10 @@
"src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h",
+ "src/proto/grpc/testing/simple_messages.grpc.pb.h",
+ "src/proto/grpc/testing/simple_messages.pb.h",
+ "src/proto/grpc/testing/simple_messages_mock.grpc.pb.h",
+ "test/cpp/end2end/test_health_check_service_impl.h",
"test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.h",
"test/cpp/util/channel_trace_proto_helper.h",
@@ -7389,6 +7460,8 @@
"language": "c++",
"name": "grpc++_test_util",
"src": [
+ "test/cpp/end2end/test_health_check_service_impl.cc",
+ "test/cpp/end2end/test_health_check_service_impl.h",
"test/cpp/end2end/test_service_impl.cc",
"test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.cc",
@@ -7430,6 +7503,10 @@
"src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h",
+ "src/proto/grpc/testing/simple_messages.grpc.pb.h",
+ "src/proto/grpc/testing/simple_messages.pb.h",
+ "src/proto/grpc/testing/simple_messages_mock.grpc.pb.h",
+ "test/cpp/end2end/test_health_check_service_impl.h",
"test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.h",
"test/cpp/util/string_ref_helper.h",
@@ -7439,6 +7516,8 @@
"language": "c++",
"name": "grpc++_test_util_unsecure",
"src": [
+ "test/cpp/end2end/test_health_check_service_impl.cc",
+ "test/cpp/end2end/test_health_check_service_impl.h",
"test/cpp/end2end/test_service_impl.cc",
"test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.cc",
@@ -7836,6 +7915,7 @@
"test/cpp/qps/report.h",
"test/cpp/qps/server.h",
"test/cpp/qps/server_async.cc",
+ "test/cpp/qps/server_callback.cc",
"test/cpp/qps/server_sync.cc",
"test/cpp/qps/stats.h",
"test/cpp/qps/usage_timer.cc",
@@ -9092,7 +9172,7 @@
"src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h",
"src/core/tsi/alts/frame_protector/frame_handler.h",
"src/core/tsi/alts/handshaker/alts_handshaker_client.h",
- "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
"src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h",
@@ -9123,8 +9203,8 @@
"src/core/tsi/alts/frame_protector/frame_handler.h",
"src/core/tsi/alts/handshaker/alts_handshaker_client.cc",
"src/core/tsi/alts/handshaker/alts_handshaker_client.h",
- "src/core/tsi/alts/handshaker/alts_tsi_event.cc",
- "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.cc",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
@@ -9604,7 +9684,8 @@
"src/core/lib/transport/status_metadata.cc",
"src/core/lib/transport/timeout_encoding.cc",
"src/core/lib/transport/transport.cc",
- "src/core/lib/transport/transport_op_string.cc"
+ "src/core/lib/transport/transport_op_string.cc",
+ "src/core/lib/uri/uri_parser.cc"
],
"third_party": false,
"type": "filegroup"
@@ -9663,6 +9744,7 @@
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
+ "src/core/lib/iomgr/dynamic_annotations.h",
"src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
@@ -9761,7 +9843,8 @@
"src/core/lib/transport/status_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
- "src/core/lib/transport/transport_impl.h"
+ "src/core/lib/transport/transport_impl.h",
+ "src/core/lib/uri/uri_parser.h"
],
"is_filegroup": true,
"language": "c",
@@ -9814,6 +9897,7 @@
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
+ "src/core/lib/iomgr/dynamic_annotations.h",
"src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
@@ -9912,7 +9996,8 @@
"src/core/lib/transport/status_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
- "src/core/lib/transport/transport_impl.h"
+ "src/core/lib/transport/transport_impl.h",
+ "src/core/lib/uri/uri_parser.h"
],
"third_party": false,
"type": "filegroup"
@@ -9981,17 +10066,16 @@
"src/core/ext/filters/client_channel/lb_policy.h",
"src/core/ext/filters/client_channel/lb_policy_factory.h",
"src/core/ext/filters/client_channel/lb_policy_registry.h",
- "src/core/ext/filters/client_channel/method_params.h",
"src/core/ext/filters/client_channel/parse_address.h",
"src/core/ext/filters/client_channel/proxy_mapper.h",
"src/core/ext/filters/client_channel/proxy_mapper_registry.h",
"src/core/ext/filters/client_channel/resolver.h",
"src/core/ext/filters/client_channel/resolver_factory.h",
"src/core/ext/filters/client_channel/resolver_registry.h",
+ "src/core/ext/filters/client_channel/resolver_result_parsing.h",
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/subchannel.h",
- "src/core/ext/filters/client_channel/subchannel_index.h",
- "src/core/ext/filters/client_channel/uri_parser.h"
+ "src/core/ext/filters/client_channel/subchannel_index.h"
],
"is_filegroup": true,
"language": "c",
@@ -10021,8 +10105,6 @@
"src/core/ext/filters/client_channel/lb_policy_factory.h",
"src/core/ext/filters/client_channel/lb_policy_registry.cc",
"src/core/ext/filters/client_channel/lb_policy_registry.h",
- "src/core/ext/filters/client_channel/method_params.cc",
- "src/core/ext/filters/client_channel/method_params.h",
"src/core/ext/filters/client_channel/parse_address.cc",
"src/core/ext/filters/client_channel/parse_address.h",
"src/core/ext/filters/client_channel/proxy_mapper.cc",
@@ -10034,14 +10116,14 @@
"src/core/ext/filters/client_channel/resolver_factory.h",
"src/core/ext/filters/client_channel/resolver_registry.cc",
"src/core/ext/filters/client_channel/resolver_registry.h",
+ "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
+ "src/core/ext/filters/client_channel/resolver_result_parsing.h",
"src/core/ext/filters/client_channel/retry_throttle.cc",
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/subchannel.cc",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_index.cc",
- "src/core/ext/filters/client_channel/subchannel_index.h",
- "src/core/ext/filters/client_channel/uri_parser.cc",
- "src/core/ext/filters/client_channel/uri_parser.h"
+ "src/core/ext/filters/client_channel/subchannel_index.h"
],
"third_party": false,
"type": "filegroup"
@@ -10685,6 +10767,7 @@
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+ "src/core/ext/transport/chttp2/transport/context_list.h",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.h",
@@ -10714,6 +10797,8 @@
"src/core/ext/transport/chttp2/transport/chttp2_plugin.cc",
"src/core/ext/transport/chttp2/transport/chttp2_transport.cc",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+ "src/core/ext/transport/chttp2/transport/context_list.cc",
+ "src/core/ext/transport/chttp2/transport/context_list.h",
"src/core/ext/transport/chttp2/transport/flow_control.cc",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h",
@@ -11060,7 +11145,6 @@
"tsi_interface"
],
"headers": [
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.h",
"src/core/tsi/ssl/session_cache/ssl_session.h",
@@ -11073,8 +11157,6 @@
"language": "c",
"name": "tsi",
"src": [
- "src/core/tsi/alts_transport_security.cc",
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.cc",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.cc",
@@ -11154,6 +11236,8 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
@@ -11166,14 +11250,18 @@
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
"include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"include/grpcpp/impl/codegen/rpc_method.h",
"include/grpcpp/impl/codegen/rpc_service_method.h",
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
+ "include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
+ "include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
@@ -11224,6 +11312,8 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
@@ -11236,14 +11326,18 @@
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
"include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"include/grpcpp/impl/codegen/rpc_method.h",
"include/grpcpp/impl/codegen/rpc_service_method.h",
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
+ "include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
+ "include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
@@ -11391,6 +11485,7 @@
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
+ "include/grpcpp/support/server_callback.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",
@@ -11495,6 +11590,7 @@
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
+ "include/grpcpp/support/server_callback.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",
@@ -11504,6 +11600,7 @@
"include/grpcpp/support/time.h",
"src/cpp/client/channel_cc.cc",
"src/cpp/client/client_context.cc",
+ "src/cpp/client/client_interceptor.cc",
"src/cpp/client/create_channel.cc",
"src/cpp/client/create_channel_internal.cc",
"src/cpp/client/create_channel_internal.h",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 145d2526e8..cc28e52ae2 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -3990,7 +3990,7 @@
"posix",
"windows"
],
- "cpu_cost": 1.0,
+ "cpu_cost": 10.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
@@ -4036,6 +4036,30 @@
"posix",
"windows"
],
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "client_interceptors_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
@@ -4114,6 +4138,30 @@
"flaky": false,
"gtest": true,
"language": "c++",
+ "name": "context_list_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": false
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
"name": "credentials_test",
"platforms": [
"linux",
@@ -5126,6 +5174,30 @@
"posix",
"windows"
],
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "server_interceptors_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index 6990244e51..e43f1fb429 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -56,6 +56,12 @@ function is_linux() {
fi
}
+function inside_venv() {
+ if [[ -n "${VIRTUAL_ENV}" ]]; then
+ echo true
+ fi
+}
+
# Associated virtual environment name for the given python command.
function venv() {
$1 -c "import sys; print('py{}{}'.format(*sys.version_info[:2]))"
@@ -80,6 +86,8 @@ function toolchain() {
fi
}
+# TODO(jtattermusch): this adds dependency on grealpath on mac
+# (brew install coreutils) for little reason.
# Command to invoke the linux command `realpath` or equivalent.
function script_realpath() {
# Find `realpath`
@@ -112,6 +120,10 @@ export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS"
export GRPC_PYTHON_BUILD_WITH_CYTHON=1
export LANG=en_US.UTF-8
+# Allow build_ext to build C/C++ files in parallel
+# by enabling a monkeypatch. It speeds up the build a lot.
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=4
+
# If ccache is available on Linux, use it.
if [ "$(is_linux)" ]; then
# We're not on Darwin (Mac OS X)
@@ -128,10 +140,14 @@ fi
# Perform build operations #
############################
-# Instantiate the virtualenv from the Python version passed in.
-$PYTHON -m pip install --user virtualenv
-$PYTHON -m virtualenv "$VENV"
-VENV_PYTHON=$(script_realpath "$VENV/$VENV_RELATIVE_PYTHON")
+if [[ "$(inside_venv)" ]]; then
+ VENV_PYTHON="$PYTHON"
+else
+ # Instantiate the virtualenv from the Python version passed in.
+ $PYTHON -m pip install --user virtualenv
+ $PYTHON -m virtualenv "$VENV"
+ VENV_PYTHON=$(script_realpath "$VENV/$VENV_RELATIVE_PYTHON")
+fi
# See https://github.com/grpc/grpc/issues/14815 for more context. We cannot rely
# on pip to upgrade itself because if pip is too old, it may not have the required
@@ -149,10 +165,13 @@ pip_install_dir() {
}
case "$VENV" in
- *gevent*)
+ *py35_gevent*)
# TODO(https://github.com/grpc/grpc/issues/15411) unpin this
$VENV_PYTHON -m pip install gevent==1.3.b1
;;
+ *gevent*)
+ $VENV_PYTHON -m pip install -U gevent
+ ;;
esac
$VENV_PYTHON -m pip install --upgrade pip==10.0.1
@@ -170,6 +189,11 @@ pip_install_dir "$ROOT"
$VENV_PYTHON "$ROOT/tools/distrib/python/make_grpcio_tools.py"
pip_install_dir "$ROOT/tools/distrib/python/grpcio_tools"
+# Build/install Channelz
+$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_channelz"
+
# Build/install health checking
$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" preprocess
$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" build_package_protos
diff --git a/tools/run_tests/performance/run_worker_csharp.sh b/tools/run_tests/performance/run_worker_csharp.sh
index 6546d6010b..bfa59b5d9e 100755
--- a/tools/run_tests/performance/run_worker_csharp.sh
+++ b/tools/run_tests/performance/run_worker_csharp.sh
@@ -18,6 +18,6 @@ set -ex
cd "$(dirname "$0")/../../.."
# needed to correctly locate testca
-cd src/csharp/Grpc.IntegrationTesting.QpsWorker/bin/Release/netcoreapp1.0
+cd src/csharp/Grpc.IntegrationTesting.QpsWorker/bin/Release/netcoreapp1.1
dotnet exec Grpc.IntegrationTesting.QpsWorker.dll "$@"
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index b732e1e03e..578712c393 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -13,8 +13,6 @@
# limitations under the License.
"""Run a group of subprocesses and then finish."""
-from __future__ import print_function
-
import logging
import multiprocessing
import os
@@ -118,7 +116,7 @@ def eintr_be_gone(fn):
while True:
try:
return fn()
- except IOError, e:
+ except IOError as e:
if e.errno != errno.EINTR:
raise
@@ -144,7 +142,7 @@ def message(tag, msg, explanatory_text=None, do_newline=False):
if do_newline or explanatory_text is not None else ''))
sys.stdout.flush()
return
- except IOError, e:
+ except IOError as e:
if e.errno != errno.EINTR:
raise
diff --git a/tools/run_tests/python_utils/port_server.py b/tools/run_tests/python_utils/port_server.py
index 83e09c09d0..243eef6827 100755
--- a/tools/run_tests/python_utils/port_server.py
+++ b/tools/run_tests/python_utils/port_server.py
@@ -14,15 +14,17 @@
# limitations under the License.
"""Manage TCP ports for unit tests; started by run_tests.py"""
+from __future__ import print_function
+
import argparse
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from six.moves.BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from six.moves.socketserver import ThreadingMixIn
import hashlib
import os
import socket
import sys
import time
import random
-from SocketServer import ThreadingMixIn
import threading
import platform
@@ -32,7 +34,7 @@ import platform
_MY_VERSION = 20
if len(sys.argv) == 2 and sys.argv[1] == 'dump_version':
- print _MY_VERSION
+ print(_MY_VERSION)
sys.exit(0)
argp = argparse.ArgumentParser(description='Server for httpcli_test')
@@ -47,7 +49,7 @@ if args.logfile is not None:
sys.stderr = open(args.logfile, 'w')
sys.stdout = sys.stderr
-print 'port server running on port %d' % args.port
+print('port server running on port %d' % args.port)
pool = []
in_use = {}
@@ -74,7 +76,7 @@ def can_connect(port):
try:
s.connect(('localhost', port))
return True
- except socket.error, e:
+ except socket.error as e:
return False
finally:
s.close()
@@ -86,7 +88,7 @@ def can_bind(port, proto):
try:
s.bind(('localhost', port))
return True
- except socket.error, e:
+ except socket.error as e:
return False
finally:
s.close()
@@ -95,7 +97,7 @@ def can_bind(port, proto):
def refill_pool(max_timeout, req):
"""Scan for ports not marked for being in use"""
chk = [
- port for port in list(range(1025, 32766))
+ port for port in range(1025, 32766)
if port not in cronet_restricted_ports
]
random.shuffle(chk)
diff --git a/tools/run_tests/python_utils/report_utils.py b/tools/run_tests/python_utils/report_utils.py
index b2a256ce29..8d8dedb929 100644
--- a/tools/run_tests/python_utils/report_utils.py
+++ b/tools/run_tests/python_utils/report_utils.py
@@ -13,8 +13,6 @@
# limitations under the License.
"""Generate XML and HTML test reports."""
-from __future__ import print_function
-
try:
from mako.runtime import Context
from mako.template import Template
diff --git a/tools/run_tests/python_utils/start_port_server.py b/tools/run_tests/python_utils/start_port_server.py
index 37995acbdf..0a32bf4418 100644
--- a/tools/run_tests/python_utils/start_port_server.py
+++ b/tools/run_tests/python_utils/start_port_server.py
@@ -12,8 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import urllib
-import jobset
+from __future__ import print_function
+
+from . import jobset
+
+import six.moves.urllib.request as request
import logging
import os
import socket
@@ -33,8 +36,8 @@ def start_port_server():
# otherwise, leave it up
try:
version = int(
- urllib.urlopen('http://localhost:%d/version_number' %
- _PORT_SERVER_PORT).read())
+ request.urlopen('http://localhost:%d/version_number' %
+ _PORT_SERVER_PORT).read())
logging.info('detected port server running version %d', version)
running = True
except Exception as e:
@@ -51,7 +54,7 @@ def start_port_server():
running = (version >= current_version)
if not running:
logging.info('port_server version mismatch: killing the old one')
- urllib.urlopen(
+ request.urlopen(
'http://localhost:%d/quitquitquit' % _PORT_SERVER_PORT).read()
time.sleep(1)
if not running:
@@ -92,7 +95,7 @@ def start_port_server():
# try one final time: maybe another build managed to start one
time.sleep(1)
try:
- urllib.urlopen(
+ request.urlopen(
'http://localhost:%d/get' % _PORT_SERVER_PORT).read()
logging.info(
'last ditch attempt to contact port server succeeded')
@@ -101,11 +104,11 @@ def start_port_server():
logging.exception(
'final attempt to contact port server failed')
port_log = open(logfile, 'r').read()
- print port_log
+ print(port_log)
sys.exit(1)
try:
port_server_url = 'http://localhost:%d/get' % _PORT_SERVER_PORT
- urllib.urlopen(port_server_url).read()
+ request.urlopen(port_server_url).read()
logging.info('port server is up and ready')
break
except socket.timeout:
diff --git a/tools/run_tests/python_utils/upload_rbe_results.py b/tools/run_tests/python_utils/upload_rbe_results.py
index 74f329048f..3f3bd382bb 100644
--- a/tools/run_tests/python_utils/upload_rbe_results.py
+++ b/tools/run_tests/python_utils/upload_rbe_results.py
@@ -62,7 +62,7 @@ def _get_invocation_id():
bazel_id_directory = os.getenv('KOKORO_ARTIFACTS_DIR')
bazel_id_file = os.path.join(bazel_id_directory, 'bazel_invocation_ids')
assert os.path.isfile(bazel_id_file), 'bazel_invocation_ids file, written ' \
- 'by bazel_wrapper.py, expected but not found.'
+ 'by RBE initialization script, expected but not found.'
with open(bazel_id_file, 'r') as f:
return f.read().replace('\n', '')
diff --git a/tools/run_tests/python_utils/watch_dirs.py b/tools/run_tests/python_utils/watch_dirs.py
index d2ad303a07..f2f1c006df 100755
--- a/tools/run_tests/python_utils/watch_dirs.py
+++ b/tools/run_tests/python_utils/watch_dirs.py
@@ -15,13 +15,14 @@
import os
import time
+from six import string_types
class DirWatcher(object):
"""Helper to watch a (set) of directories for modifications."""
def __init__(self, paths):
- if isinstance(paths, basestring):
+ if isinstance(paths, string_types):
paths = [paths]
self._done = False
self.paths = list(paths)
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 5722a88182..d026145d66 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -63,17 +63,17 @@ _SKIP_ADVANCED = [
'unimplemented_service'
]
+_SKIP_SPECIAL_STATUS_MESSAGE = ['special_status_message']
+
_TEST_TIMEOUT = 3 * 60
# disable this test on core-based languages,
# see https://github.com/grpc/grpc/issues/9779
_SKIP_DATA_FRAME_PADDING = ['data_frame_padding']
-# report suffix is important for reports to get picked up by internal CI
-_INTERNAL_CL_XML_REPORT = 'sponge_log.xml'
-
-# report suffix is important for reports to get picked up by internal CI
-_XML_REPORT = 'report.xml'
+# report suffix "sponge_log.xml" is important for reports to get picked up by internal CI
+_DOCKER_BUILD_XML_REPORT = 'interop_docker_build/sponge_log.xml'
+_TESTS_XML_REPORT = 'interop_test/sponge_log.xml'
class CXXLanguage:
@@ -100,7 +100,7 @@ class CXXLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_DATA_FRAME_PADDING
+ return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -129,7 +129,7 @@ class CSharpLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -141,8 +141,8 @@ class CSharpLanguage:
class CSharpCoreCLRLanguage:
def __init__(self):
- self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0'
- self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug/netcoreapp1.0'
+ self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1'
+ self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug/netcoreapp1.1'
self.safename = str(self)
def client_cmd(self, args):
@@ -158,7 +158,7 @@ class CSharpCoreCLRLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -188,10 +188,10 @@ class DartLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION
+ return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
- return _SKIP_COMPRESSION
+ return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE
def __str__(self):
return 'dart'
@@ -248,7 +248,7 @@ class JavaOkHttpClient:
return {}
def unimplemented_test_cases(self):
- return _SKIP_DATA_FRAME_PADDING
+ return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def __str__(self):
return 'javaokhttp'
@@ -309,7 +309,7 @@ class Http2Server:
return {}
def unimplemented_test_cases(self):
- return _TEST_CASES + _SKIP_DATA_FRAME_PADDING
+ return _TEST_CASES + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _TEST_CASES
@@ -339,7 +339,7 @@ class Http2Client:
return {}
def unimplemented_test_cases(self):
- return _TEST_CASES
+ return _TEST_CASES + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _TEST_CASES
@@ -431,7 +431,7 @@ class PHPLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -456,7 +456,7 @@ class PHP7Language:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -491,7 +491,7 @@ class ObjcLanguage:
# cmdline argument. Here we return all but one test cases as unimplemented,
# and depend upon ObjC test's behavior that it runs all cases even when
# we tell it to run just one.
- return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -526,7 +526,7 @@ class RubyLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -545,13 +545,13 @@ class PythonLanguage:
def client_cmd(self, args):
return [
- 'py27_native/bin/python', 'src/python/grpcio_tests/setup.py',
+ 'py37_native/bin/python', 'src/python/grpcio_tests/setup.py',
'run_interop', '--client', '--args="{}"'.format(' '.join(args))
]
def client_cmd_http2interop(self, args):
return [
- 'py27_native/bin/python',
+ 'py37_native/bin/python',
'src/python/grpcio_tests/tests/http2/negative_http2_client.py',
] + args
@@ -560,7 +560,7 @@ class PythonLanguage:
def server_cmd(self, args):
return [
- 'py27_native/bin/python', 'src/python/grpcio_tests/setup.py',
+ 'py37_native/bin/python', 'src/python/grpcio_tests/setup.py',
'run_interop', '--server', '--args="{}"'.format(' '.join(args))
]
@@ -610,7 +610,7 @@ _TEST_CASES = [
'custom_metadata', 'status_code_and_message', 'unimplemented_method',
'client_compressed_unary', 'server_compressed_unary',
'client_compressed_streaming', 'server_compressed_streaming',
- 'unimplemented_service'
+ 'unimplemented_service', 'special_status_message'
]
_AUTH_TEST_CASES = [
@@ -1161,8 +1161,9 @@ argp.add_argument(
default=False,
action='store_const',
const=True,
- help=('Put reports into subdirectories to improve '
- 'presentation of results by Internal CI.'))
+ help=(
+ '(Deprecated, has no effect) Put reports into subdirectories to improve '
+ 'presentation of results by Internal CI.'))
argp.add_argument(
'--bq_result_table',
default='',
@@ -1251,8 +1252,12 @@ if args.use_docker:
if args.verbose:
print('Jobs to run: \n%s\n' % '\n'.join(str(j) for j in build_jobs))
- num_failures, _ = jobset.run(
+ num_failures, build_resultset = jobset.run(
build_jobs, newline_on_success=True, maxjobs=args.jobs)
+
+ report_utils.render_junit_xml_report(build_resultset,
+ _DOCKER_BUILD_XML_REPORT)
+
if num_failures == 0:
jobset.message(
'SUCCESS',
@@ -1315,7 +1320,7 @@ try:
for language in languages:
for test_case in _TEST_CASES:
if not test_case in language.unimplemented_test_cases():
- if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
+ if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE:
tls_test_job = cloud_to_prod_jobspec(
language,
test_case,
@@ -1517,10 +1522,7 @@ try:
write_cmdlog_maybe(server_manual_cmd_log, 'interop_server_cmds.sh')
write_cmdlog_maybe(client_manual_cmd_log, 'interop_client_cmds.sh')
- xml_report_name = _XML_REPORT
- if args.internal_ci:
- xml_report_name = _INTERNAL_CL_XML_REPORT
- report_utils.render_junit_xml_report(resultset, xml_report_name)
+ report_utils.render_junit_xml_report(resultset, _TESTS_XML_REPORT)
for name, job in resultset.items():
if "http2" in name:
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 44151f49fb..2556e77773 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -756,19 +756,23 @@ class PythonLanguage(object):
def dockerfile_dir(self):
return 'tools/dockerfile/test/python_%s_%s' % (
- self.python_manager_name(), _docker_arch_suffix(self.args.arch))
+ self._python_manager_name(), _docker_arch_suffix(self.args.arch))
- def python_manager_name(self):
+ def _python_manager_name(self):
+ """Choose the docker image to use based on python version."""
if self.args.compiler in [
'python2.7', 'python3.5', 'python3.6', 'python3.7'
]:
return 'stretch_' + self.args.compiler[len('python'):]
elif self.args.compiler == 'python_alpine':
return 'alpine'
- else:
+ elif self.args.compiler == 'python3.4':
return 'jessie'
+ else:
+ return 'stretch_3.7'
def _get_pythons(self, args):
+ """Get python runtimes to test with, based on current platform, architecture, compiler etc."""
if args.arch == 'x86':
bits = '32'
else:
@@ -844,7 +848,7 @@ class PythonLanguage(object):
else:
return (
python27_config,
- python34_config,
+ python37_config,
)
elif args.compiler == 'python2.7':
return (python27_config,)
@@ -938,7 +942,7 @@ class CSharpLanguage(object):
self._cmake_arch_option = 'x64'
else:
_check_compiler(self.args.compiler, ['default', 'coreclr'])
- self._docker_distro = 'jessie'
+ self._docker_distro = 'stretch'
def test_specs(self):
with open('src/csharp/tests.json') as f:
@@ -950,7 +954,7 @@ class CSharpLanguage(object):
assembly_extension = '.exe'
if self.args.compiler == 'coreclr':
- assembly_subdir += '/netcoreapp1.0'
+ assembly_subdir += '/netcoreapp1.1'
runtime_cmd = ['dotnet', 'exec']
assembly_extension = '.dll'
else:
@@ -1338,9 +1342,9 @@ argp.add_argument(
argp.add_argument(
'-l',
'--language',
- choices=['all'] + sorted(_LANGUAGES.keys()),
+ choices=sorted(_LANGUAGES.keys()),
nargs='+',
- default=['all'])
+ required=True)
argp.add_argument(
'-S', '--stop_on_failure', default=False, action='store_const', const=True)
argp.add_argument(
@@ -1511,17 +1515,7 @@ build_config = run_config.build_config
if args.travis:
_FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
-if 'all' in args.language:
- lang_list = _LANGUAGES.keys()
-else:
- lang_list = args.language
-# We don't support code coverage on some languages
-if 'gcov' in args.config:
- for bad in ['csharp', 'grpc-node', 'objc', 'sanity']:
- if bad in lang_list:
- lang_list.remove(bad)
-
-languages = set(_LANGUAGES[l] for l in lang_list)
+languages = set(_LANGUAGES[l] for l in args.language)
for l in languages:
l.configure(run_config, args)
@@ -1533,7 +1527,7 @@ if any(language.make_options() for language in languages):
)
sys.exit(1)
else:
- # Combining make options is not clean and just happens to work. It allows C/C++ and C# to build
+ # Combining make options is not clean and just happens to work. It allows C & C++ to build
# together, and is only used under gcov. All other configs should build languages individually.
language_make_options = list(
set([
@@ -1556,16 +1550,9 @@ if args.use_docker:
dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
if len(dockerfile_dirs) > 1:
- if 'gcov' in args.config:
- dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
- print(
- 'Using multilang_jessie_x64 docker image for code coverage for '
- 'all languages.')
- else:
- print(
- 'Languages to be tested require running under different docker '
- 'images.')
- sys.exit(1)
+ print('Languages to be tested require running under different docker '
+ 'images.')
+ sys.exit(1)
else:
dockerfile_dir = next(iter(dockerfile_dirs))
@@ -1719,9 +1706,9 @@ def _has_epollexclusive():
try:
subprocess.check_call(binary)
return True
- except subprocess.CalledProcessError, e:
+ except subprocess.CalledProcessError as e:
return False
- except OSError, e:
+ except OSError as e:
# For languages other than C and Windows the binary won't exist
return False
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 00fc68ad17..d93add00cd 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -574,11 +574,8 @@ if __name__ == "__main__":
print('Will run these tests:')
for job in jobs:
- if args.dry_run:
- print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
- else:
- print(' %s' % job.shortname)
- print
+ print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
+ print('')
if args.dry_run:
print('--dry_run was used, exiting')
diff --git a/tools/run_tests/sanity/check_bazel_workspace.py b/tools/run_tests/sanity/check_bazel_workspace.py
index d562fffc8a..1486d0bd27 100755
--- a/tools/run_tests/sanity/check_bazel_workspace.py
+++ b/tools/run_tests/sanity/check_bazel_workspace.py
@@ -42,6 +42,7 @@ _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME = 'com_github_zopefoundation_zope_interf
_TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly'
_GRPC_DEP_NAMES = [
+ 'upb',
'boringssl',
'com_github_madler_zlib',
'com_google_protobuf',
@@ -110,6 +111,8 @@ bazel_file += '\ngrpc_deps()\n'
bazel_file += '\ngrpc_test_only_deps()\n'
build_rules = {
'native': eval_state,
+ 'http_archive': lambda **args: eval_state.http_archive(**args),
+ 'load': lambda a, b: None,
}
exec bazel_file in build_rules
for name in _GRPC_DEP_NAMES:
@@ -149,6 +152,8 @@ for name in _GRPC_DEP_NAMES:
names_and_urls_with_overridden_name, overridden_name=name)
rules = {
'native': state,
+ 'http_archive': lambda **args: state.http_archive(**args),
+ 'load': lambda a, b: None,
}
exec bazel_file in rules
assert name not in names_and_urls_with_overridden_name.keys()
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 2c7c140716..f1103596d5 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -30,13 +30,17 @@ cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8 third_party/benchmark (v1.2.0)
73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty (remotes/origin/wide-14-g73594cd)
b29b21a81b32ec273f118f589f46d56ad3332420 third_party/boringssl (remotes/origin/chromium-stable)
- 8149b351bf797bd80e063787886b7618f508e451 third_party/boringssl-with-bazel (version_for_cocoapods_10.0-434-g8149b351)
+ afc30d43eef92979b05776ec0963c9cede5fb80f third_party/boringssl-with-bazel (fips-20180716-116-gafc30d43e)
3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0)
+ 911001cdca003337bdb93fab32740cde61bafee3 third_party/data-plane-api (heads/master)
30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0-5-g30dbc81)
+ 80ed4d0bbf65d57cc267dfc63bd2584557f11f9b third_party/googleapis (common-protos-1_3_1-915-g80ed4d0bb)
ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
6599cac0965be8e5a835ab7a5684bbef033d5ad0 third_party/libcxx (heads/release_60)
9245d481eb3e890f708ff2d7dadf2a10c04748ba third_party/libcxxabi (heads/release_60)
48cb18e5c419ddd23d9badcfe4e9df7bde1979b2 third_party/protobuf (v3.6.0.1-37-g48cb18e5)
+ e143189bf6f37b3957fb31743df6a1bcf4a8c685 third_party/protoc-gen-validate (v0.0.10)
+ 9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3 third_party/upb (heads/upbc-cpp)
cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
EOF
diff --git a/tools/run_tests/sanity/core_banned_functions.py b/tools/run_tests/sanity/core_banned_functions.py
index 8afd826453..549ae14f5a 100755
--- a/tools/run_tests/sanity/core_banned_functions.py
+++ b/tools/run_tests/sanity/core_banned_functions.py
@@ -24,7 +24,8 @@ os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
# map of banned function signature to whitelist
BANNED_EXCEPT = {
'grpc_resource_quota_ref(': ['src/core/lib/iomgr/resource_quota.cc'],
- 'grpc_resource_quota_unref(': ['src/core/lib/iomgr/resource_quota.cc'],
+ 'grpc_resource_quota_unref(':
+ ['src/core/lib/iomgr/resource_quota.cc', 'src/core/lib/surface/server.cc'],
'grpc_slice_buffer_destroy(': ['src/core/lib/slice/slice_buffer.cc'],
'grpc_slice_buffer_reset_and_unref(':
['src/core/lib/slice/slice_buffer.cc'],
@@ -38,6 +39,7 @@ BANNED_EXCEPT = {
'grpc_wsa_error(': ['src/core/lib/iomgr/error.cc'],
'grpc_log_if_error(': ['src/core/lib/iomgr/error.cc'],
'grpc_slice_malloc(': ['src/core/lib/slice/slice.cc'],
+ 'grpc_call_cancel_internal(': ['src/core/lib/surface/call.cc'],
'grpc_closure_create(': ['src/core/lib/iomgr/closure.cc'],
'grpc_closure_init(': ['src/core/lib/iomgr/closure.cc'],
'grpc_closure_sched(': ['src/core/lib/iomgr/closure.cc'],