Imported Upstream version 1.22.0 upstream/1.22.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 3 Mar 2020 00:41:05 +0000 (09:41 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 3 Mar 2020 00:41:05 +0000 (09:41 +0900)
486 files changed:
.gitignore
BUILD
BUILD.gn
CMakeLists.txt
Makefile
Rakefile
bazel/generate_cc.bzl
bazel/grpc_deps.bzl
bazel/python_rules.bzl
build.yaml
doc/environment_variables.md
doc/g_stands_for.md
doc/health-checking.md
doc/server_side_auth.md
examples/cpp/helloworld/Makefile
examples/cpp/route_guide/Makefile
examples/python/debug/BUILD.bazel [new file with mode: 0644]
examples/python/debug/README.md [new file with mode: 0644]
examples/python/debug/debug_server.py [new file with mode: 0644]
examples/python/debug/get_stats.py [new file with mode: 0644]
examples/python/debug/send_message.py [new file with mode: 0644]
examples/python/debug/test/_debug_example_test.py [new file with mode: 0644]
gRPC-C++.podspec
gRPC-Core.podspec
gRPC-ProtoRPC.podspec
gRPC-RxLibrary.podspec
gRPC.podspec
grpc.def
grpc.gemspec
grpc.gyp
include/grpc/grpc_security.h
include/grpc/grpc_security_constants.h
include/grpc/impl/codegen/gpr_types.h
include/grpc/slice.h
include/grpcpp/channel_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call_op_set.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h [new file with mode: 0644]
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/config_protobuf.h
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/proto_utils.h
include/grpcpp/impl/codegen/rpc_service_method.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h [new file with mode: 0644]
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/opencensus.h
include/grpcpp/opencensus_impl.h
include/grpcpp/server_builder_impl.h
include/grpcpp/server_impl.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/validate_service_config.h [new file with mode: 0644]
package.xml
requirements.bazel.txt
requirements.txt
src/compiler/cpp_generator.cc
src/compiler/csharp_generator.cc
src/compiler/csharp_generator.h
src/compiler/csharp_plugin.cc
src/core/ext/filters/client_channel/backup_poller.cc
src/core/ext/filters/client_channel/backup_poller.h
src/core/ext/filters/client_channel/client_channel.cc
src/core/ext/filters/client_channel/client_channel.h
src/core/ext/filters/client_channel/client_channel_channelz.cc
src/core/ext/filters/client_channel/client_channel_channelz.h
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy.h
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.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/resolver.h
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
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/resolving_lb_policy.cc
src/core/ext/filters/client_channel/resolving_lb_policy.h
src/core/ext/filters/client_channel/server_address.cc
src/core/ext/filters/client_channel/server_address.h
src/core/ext/filters/client_channel/service_config.cc
src/core/ext/filters/client_channel/service_config.h
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel.h
src/core/ext/filters/client_channel/subchannel_interface.h [new file with mode: 0644]
src/core/ext/filters/message_size/message_size_filter.cc
src/core/ext/filters/message_size/message_size_filter.h
src/core/ext/transport/chttp2/server/chttp2_server.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/hpack_table.h
src/core/ext/transport/chttp2/transport/internal.h
src/core/ext/transport/chttp2/transport/parsing.cc
src/core/ext/transport/cronet/transport/cronet_transport.cc
src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz.h
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/channelz_registry.h
src/core/lib/channel/context.h
src/core/lib/channel/handshaker.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/compression_internal.h
src/core/lib/compression/stream_compression.cc
src/core/lib/compression/stream_compression.h
src/core/lib/compression/stream_compression_gzip.cc
src/core/lib/gpr/env.h
src/core/lib/gpr/string.cc
src/core/lib/gpr/string.h
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/fork.h
src/core/lib/gprpp/global_config.h
src/core/lib/gprpp/global_config_custom.h
src/core/lib/gprpp/inlined_vector.h
src/core/lib/gprpp/map.h
src/core/lib/gprpp/memory.h
src/core/lib/gprpp/orphanable.h
src/core/lib/gprpp/ref_counted.h
src/core/lib/http/httpcli.cc
src/core/lib/iomgr/buffer_list.h
src/core/lib/iomgr/call_combiner.cc
src/core/lib/iomgr/call_combiner.h
src/core/lib/iomgr/cfstream_handle.cc
src/core/lib/iomgr/cfstream_handle.h
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/error.h
src/core/lib/iomgr/error_internal.h
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_posix.h
src/core/lib/iomgr/ev_windows.cc
src/core/lib/iomgr/iomgr.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/port.h
src/core/lib/iomgr/tcp_posix.cc
src/core/lib/iomgr/tcp_server.cc
src/core/lib/iomgr/tcp_server.h
src/core/lib/iomgr/tcp_server_custom.cc
src/core/lib/iomgr/tcp_server_posix.cc
src/core/lib/iomgr/tcp_server_utils_posix.h
src/core/lib/iomgr/tcp_server_windows.cc
src/core/lib/iomgr/tcp_uv.cc
src/core/lib/iomgr/timer.h
src/core/lib/iomgr/udp_server.cc
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.h
src/core/lib/security/security_connector/security_connector.h
src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
src/core/lib/security/transport/auth_filters.h
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/security_handshaker.cc
src/core/lib/slice/b64.h
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.h
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_internal.h
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/slice/slice_string_helpers.h
src/core/lib/slice/slice_utils.h [new file with mode: 0644]
src/core/lib/slice/slice_weak_hash_table.h
src/core/lib/surface/call.cc
src/core/lib/surface/channel.cc
src/core/lib/surface/channel.h
src/core/lib/surface/completion_queue.cc
src/core/lib/surface/completion_queue.h
src/core/lib/surface/server.cc
src/core/lib/surface/validate_metadata.cc
src/core/lib/surface/validate_metadata.h
src/core/lib/surface/version.cc
src/core/lib/transport/metadata.cc
src/core/lib/transport/metadata.h
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/static_metadata.h
src/core/lib/transport/transport.cc
src/core/lib/transport/transport.h
src/core/tsi/alts/handshaker/alts_shared_resource.h
src/cpp/client/channel_cc.cc
src/cpp/client/client_context.cc
src/cpp/client/create_channel.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/channel_filter.cc
src/cpp/common/validate_service_config.cc [new file with mode: 0644]
src/cpp/common/version_cc.cc
src/cpp/ext/filters/census/grpc_plugin.h
src/cpp/server/external_connection_acceptor_impl.cc [new file with mode: 0644]
src/cpp/server/external_connection_acceptor_impl.h [new file with mode: 0644]
src/cpp/server/server_builder.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/thread_manager/thread_manager.h
src/csharp/BUILD-INTEGRATION.md
src/csharp/Grpc.Core.Api/Interceptors/CallInvokerExtensions.cs [moved from src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs with 100% similarity]
src/csharp/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs [moved from src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs with 100% similarity]
src/csharp/Grpc.Core.Api/LiteClientBase.cs [new file with mode: 0644]
src/csharp/Grpc.Core.Api/VersionInfo.cs
src/csharp/Grpc.Core/ForwardedTypes.cs
src/csharp/Grpc.Core/ServerCredentials.cs
src/csharp/Grpc.Core/Version.csproj.include
src/csharp/Grpc.Examples/MathWithProtocOptions.cs [new file with mode: 0644]
src/csharp/Grpc.Examples/MathWithProtocOptionsGrpc.cs [new file with mode: 0644]
src/csharp/Grpc.Examples/math_with_protoc_options.proto [new file with mode: 0644]
src/csharp/Grpc.IntegrationTesting/EchoMessages.cs
src/csharp/Grpc.IntegrationTesting/InteropClient.cs
src/csharp/Grpc.Tools/ProtoCompile.cs
src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml
src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets
src/csharp/README.md
src/csharp/build/dependencies.props
src/csharp/build_unitypackage.bat
src/csharp/docfx/.gitignore [moved from src/csharp/doc/.gitignore with 100% similarity]
src/csharp/docfx/README.md [moved from src/csharp/doc/README.md with 100% similarity]
src/csharp/docfx/docfx.json [moved from src/csharp/doc/docfx.json with 100% similarity]
src/csharp/docfx/generate_reference_docs.sh [moved from src/csharp/doc/generate_reference_docs.sh with 90% similarity]
src/csharp/docfx/toc.yml [moved from src/csharp/doc/toc.yml with 100% similarity]
src/csharp/generate_proto_csharp.sh
src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
src/objective-c/!ProtoCompiler.podspec
src/objective-c/GRPCClient/GRPCCall.h
src/objective-c/GRPCClient/GRPCCall.m
src/objective-c/GRPCClient/GRPCCallOptions.h
src/objective-c/GRPCClient/GRPCCallOptions.m
src/objective-c/GRPCClient/GRPCInterceptor.h [new file with mode: 0644]
src/objective-c/GRPCClient/GRPCInterceptor.m [new file with mode: 0644]
src/objective-c/GRPCClient/private/GRPCCall+V2API.h [new file with mode: 0644]
src/objective-c/GRPCClient/private/GRPCCallInternal.h [new file with mode: 0644]
src/objective-c/GRPCClient/private/GRPCCallInternal.m [new file with mode: 0644]
src/objective-c/GRPCClient/private/version.h
src/objective-c/ProtoRPC/ProtoRPC.m
src/objective-c/examples/InterceptorSample/InterceptorSample.xcodeproj/project.pbxproj [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/AppDelegate.h [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/AppDelegate.m [moved from src/objective-c/tests/Tests.m with 82% similarity]
src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/AppIcon.appiconset/Contents.json [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/Contents.json [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/LaunchScreen.storyboard [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/Main.storyboard [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.h [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.m [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/Info.plist [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.h [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.m [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/InterceptorSample/main.m [new file with mode: 0644]
src/objective-c/examples/InterceptorSample/Podfile [new file with mode: 0644]
src/objective-c/tests/APIv2Tests/Info.plist [deleted file]
src/objective-c/tests/ChannelTests/Info.plist [deleted file]
src/objective-c/tests/ConfigureCronet.h [new file with mode: 0644]
src/objective-c/tests/ConfigureCronet.m [new file with mode: 0644]
src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist [deleted file]
src/objective-c/tests/CronetTests/CoreCronetEnd2EndTests.mm [moved from src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm with 96% similarity]
src/objective-c/tests/CronetTests/CronetUnitTests.mm [moved from src/objective-c/tests/CronetUnitTests/CronetUnitTests.m with 96% similarity]
src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m [moved from src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m with 97% similarity]
src/objective-c/tests/CronetUnitTests/Info.plist [deleted file]
src/objective-c/tests/InteropTests/InteropTests.h [moved from src/objective-c/tests/InteropTests.h with 95% similarity]
src/objective-c/tests/InteropTests/InteropTests.m [moved from src/objective-c/tests/InteropTests.m with 62% similarity]
src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.h [new file with mode: 0644]
src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.m [new file with mode: 0644]
src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m [moved from src/objective-c/tests/InteropTestsLocalCleartext.m with 100% similarity]
src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m [moved from src/objective-c/tests/InteropTestsLocalSSL.m with 100% similarity]
src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m [new file with mode: 0644]
src/objective-c/tests/InteropTests/InteropTestsRemote.m [moved from src/objective-c/tests/InteropTestsRemote.m with 100% similarity]
src/objective-c/tests/InteropTestsCallOptions/Info.plist [deleted file]
src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m [deleted file]
src/objective-c/tests/InteropTestsMultipleChannels/Info.plist [deleted file]
src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m [deleted file]
src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist [deleted file]
src/objective-c/tests/MacTests/StressTests.m
src/objective-c/tests/Podfile
src/objective-c/tests/Tests.xcodeproj/project.pbxproj
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetTests.xcscheme [moved from src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme with 74% similarity]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetUnitTests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme [moved from src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme with 75% similarity]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartextCFStream.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSLCFStream.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteCFStream.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/MacTests.xcscheme
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme [deleted file]
src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme
src/objective-c/tests/UnitTests/APIv2Tests.m [moved from src/objective-c/tests/APIv2Tests/APIv2Tests.m with 100% similarity]
src/objective-c/tests/UnitTests/ChannelPoolTest.m [moved from src/objective-c/tests/ChannelTests/ChannelPoolTest.m with 100% similarity]
src/objective-c/tests/UnitTests/ChannelTests.m [moved from src/objective-c/tests/ChannelTests/ChannelTests.m with 100% similarity]
src/objective-c/tests/UnitTests/GRPCClientTests.m [moved from src/objective-c/tests/GRPCClientTests.m with 99% similarity]
src/objective-c/tests/UnitTests/Info.plist [deleted file]
src/objective-c/tests/UnitTests/NSErrorUnitTests.m [moved from src/objective-c/tests/UnitTests/UnitTests.m with 96% similarity]
src/objective-c/tests/UnitTests/RxLibraryUnitTests.m [moved from src/objective-c/tests/RxLibraryUnitTests.m with 100% similarity]
src/objective-c/tests/examples_build_test.sh [moved from tools/internal_ci/macos/grpc_interop.sh with 57% similarity]
src/objective-c/tests/run_tests.sh
src/objective-c/tests/version.h
src/php/README.md
src/php/composer.json
src/php/ext/grpc/channel.c
src/php/ext/grpc/version.h
src/php/lib/Grpc/BaseStub.php
src/php/tests/generated_code/AbstractGeneratedCodeTest.php
src/php/tests/generated_code/math_server.js [new file with mode: 0644]
src/php/tests/generated_code/package.json [new file with mode: 0644]
src/php/tests/interop/interop_client.php
src/proto/grpc/testing/BUILD
src/python/grpcio/README.rst
src/python/grpcio/grpc/__init__.py
src/python/grpcio/grpc/_channel.py
src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd.pxi
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
src/python/grpcio/grpc/_grpcio_metadata.py
src/python/grpcio/grpc_version.py
src/python/grpcio_channelz/grpc_version.py
src/python/grpcio_health_checking/grpc_version.py
src/python/grpcio_reflection/grpc_version.py
src/python/grpcio_status/grpc_version.py
src/python/grpcio_testing/grpc_version.py
src/python/grpcio_tests/grpc_version.py
src/ruby/ext/grpc/rb_grpc_imports.generated.c
src/ruby/ext/grpc/rb_grpc_imports.generated.h
src/ruby/lib/grpc/version.rb
src/ruby/tools/version.rb
templates/CMakeLists.txt.template
templates/grpc.gemspec.template
templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template
templates/test/core/end2end/end2end_defs.include
templates/tools/dockerfile/bazel.include
templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template
templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.include [moved from templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile.include with 63% similarity]
templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
templates/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh.template
templates/tools/dockerfile/interoptest/grpc_interop_java/java_deps.include [deleted file]
templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile.template [deleted file]
templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh.template [deleted file]
templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/java_deps.include [deleted file]
templates/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile.template [new file with mode: 0644]
test/core/bad_client/gen_build_yaml.py
test/core/bad_client/generate_tests.bzl
test/core/bad_client/tests/unknown_frame.cc
test/core/channel/channel_trace_test.cc
test/core/channel/channelz_registry_test.cc
test/core/channel/channelz_test.cc
test/core/client_channel/service_config_test.cc
test/core/end2end/end2end_nosec_tests.cc
test/core/end2end/end2end_tests.cc
test/core/gprpp/inlined_vector_test.cc
test/core/gprpp/map_test.cc
test/core/slice/slice_buffer_test.cc
test/core/slice/slice_test.cc
test/core/surface/completion_queue_test.cc
test/core/surface/public_headers_must_be_c89.c
test/core/util/debugger_macros.cc
test/core/util/debugger_macros.h
test/core/util/test_lb_policies.cc
test/core/util/test_tcp_server.cc
test/cpp/codegen/compiler_test_golden
test/cpp/end2end/BUILD
test/cpp/end2end/cfstream_test.cc
test/cpp/end2end/channelz_service_test.cc
test/cpp/end2end/client_callback_end2end_test.cc
test/cpp/end2end/client_interceptors_end2end_test.cc
test/cpp/end2end/client_lb_end2end_test.cc
test/cpp/end2end/end2end_test.cc
test/cpp/end2end/flaky_network_test.cc
test/cpp/end2end/grpclb_end2end_test.cc
test/cpp/end2end/interceptors_util.cc
test/cpp/end2end/interceptors_util.h
test/cpp/end2end/message_allocator_end2end_test.cc
test/cpp/end2end/port_sharing_end2end_test.cc [new file with mode: 0644]
test/cpp/end2end/server_interceptors_end2end_test.cc
test/cpp/end2end/service_config_end2end_test.cc
test/cpp/end2end/test_health_check_service_impl.cc
test/cpp/end2end/xds_end2end_test.cc
test/cpp/interop/BUILD
test/cpp/microbenchmarks/BUILD
test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc [new file with mode: 0644]
test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc [new file with mode: 0644]
test/cpp/microbenchmarks/bm_chttp2_transport.cc
test/cpp/microbenchmarks/bm_cq.cc
test/cpp/microbenchmarks/callback_streaming_ping_pong.h [new file with mode: 0644]
test/cpp/microbenchmarks/callback_test_service.cc [new file with mode: 0644]
test/cpp/microbenchmarks/callback_test_service.h [new file with mode: 0644]
test/cpp/microbenchmarks/callback_unary_ping_pong.h [new file with mode: 0644]
test/cpp/qps/client_async.cc
test/cpp/qps/client_callback.cc
test/cpp/util/BUILD
test/cpp/util/cli_call.h
test/cpp/util/test_credentials_provider.cc
third_party/zlib.BUILD
tools/bazel [new file with mode: 0755]
tools/codegen/core/gen_static_metadata.py
tools/distrib/python/grpcio_tools/grpc_version.py
tools/distrib/python/grpcio_tools/protoc_lib_deps.py
tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_2/Dockerfile [deleted file]
tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile
tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile
tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile [deleted file]
tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh [deleted file]
tools/dockerfile/test/bazel/Dockerfile
tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile [new file with mode: 0644]
tools/dockerfile/test/python_stretch_3.8_x64/get_cpython.sh [new file with mode: 0644]
tools/dockerfile/test/sanity/Dockerfile
tools/doxygen/Doxyfile.c++
tools/doxygen/Doxyfile.c++.internal
tools/doxygen/Doxyfile.core.internal
tools/internal_ci/helper_scripts/prepare_build_interop_rc
tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
tools/internal_ci/helper_scripts/prepare_build_macos_rc
tools/internal_ci/helper_scripts/prepare_build_windows.bat
tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh
tools/internal_ci/linux/grpc_flaky_network_in_docker.sh
tools/internal_ci/linux/grpc_interop_toprod.cfg
tools/internal_ci/linux/grpc_microbenchmark_diff.sh
tools/internal_ci/linux/grpc_run_tests_matrix.sh
tools/internal_ci/linux/grpc_trickle_diff.sh
tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_build_only.cfg [moved from tools/internal_ci/macos/grpc_interop.cfg with 75% similarity]
tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg
tools/internal_ci/linux/run_if_c_cpp_modified.sh
tools/internal_ci/macos/grpc_interop_toprod.cfg
tools/internal_ci/macos/grpc_interop_toprod.sh
tools/internal_ci/macos/grpc_ios_binary_size.sh
tools/internal_ci/windows/bazel_rbe.bat
tools/interop_matrix/README.md
tools/interop_matrix/client_matrix.py
tools/interop_matrix/create_testcases.sh
tools/interop_matrix/run_interop_matrix_tests.py
tools/interop_matrix/testcases/cxx__master
tools/interop_matrix/testcases/cxx__v1.0.1 [new file with mode: 0755]
tools/interop_matrix/testcases/go__master
tools/interop_matrix/testcases/go__v1.0.5 [new file with mode: 0755]
tools/interop_matrix/testcases/java__master
tools/interop_matrix/testcases/java__v1.0.3 [new file with mode: 0755]
tools/interop_matrix/testcases/php__master
tools/interop_matrix/testcases/php__v1.0.1 [new file with mode: 0755]
tools/interop_matrix/testcases/python__master
tools/interop_matrix/testcases/ruby__master
tools/interop_matrix/testcases/ruby__v1.1.4 [new file with mode: 0755]
tools/remote_build/rbe_common.bazelrc
tools/run_tests/artifacts/distribtest_targets.py
tools/run_tests/generated/sources_and_headers.json
tools/run_tests/generated/tests.json
tools/run_tests/run_interop_tests.py
tools/run_tests/run_tests.py
tools/run_tests/sanity/check_bazel_workspace.py
tools/run_tests/sanity/check_submodules.sh
tools/run_tests/start_port_server.py

index 7b4c5d3..a8c5827 100644 (file)
@@ -109,13 +109,14 @@ Podfile.lock
 # IDE specific folder for JetBrains IDEs
 .idea/
 
-# Blaze files
+# Bazel files
 bazel-bin
 bazel-genfiles
 bazel-grpc
 bazel-out
 bazel-testlogs
 bazel_format_virtual_environment/
+tools/bazel-*
 
 # Debug output
 gdb.txt
@@ -143,3 +144,5 @@ bm_*.json
 !.vscode/launch.json
 !.vscode/extensions.json
 
+# Clion artifacts
+cmake-build-debug/
diff --git a/BUILD b/BUILD
index af1d784..f08703a 100644 (file)
--- a/BUILD
+++ b/BUILD
@@ -74,11 +74,11 @@ config_setting(
 )
 
 # This should be updated along with build.yaml
-g_stands_for = "gandalf"
+g_stands_for = "gale"
 
 core_version = "7.0.0"
 
-version = "1.21.3"
+version = "1.22.0"
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
@@ -137,10 +137,12 @@ GRPCXX_SRCS = [
     "src/cpp/common/resource_quota_cc.cc",
     "src/cpp/common/rpc_method.cc",
     "src/cpp/common/version_cc.cc",
+    "src/cpp/common/validate_service_config.cc",    
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/channel_argument_option.cc",
     "src/cpp/server/create_default_thread_pool.cc",
     "src/cpp/server/dynamic_thread_pool.cc",
+    "src/cpp/server/external_connection_acceptor_impl.cc",
     "src/cpp/server/health/default_health_check_service.cc",
     "src/cpp/server/health/health_check_service.cc",
     "src/cpp/server/health/health_check_service_server_builder_option.cc",
@@ -160,6 +162,7 @@ GRPCXX_HDRS = [
     "src/cpp/client/create_channel_internal.h",
     "src/cpp/common/channel_filter.h",
     "src/cpp/server/dynamic_thread_pool.h",
+    "src/cpp/server/external_connection_acceptor_impl.h",
     "src/cpp/server/health/default_health_check_service.h",
     "src/cpp/server/thread_pool_interface.h",
     "src/cpp/thread_manager/thread_manager.h",
@@ -284,6 +287,7 @@ GRPCXX_PUBLIC_HDRS = [
     "include/grpcpp/support/stub_options.h",
     "include/grpcpp/support/sync_stream.h",
     "include/grpcpp/support/time.h",
+    "include/grpcpp/support/validate_service_config.h",    
 ]
 
 grpc_cc_library(
@@ -997,6 +1001,7 @@ grpc_cc_library(
         "src/core/lib/slice/slice_hash_table.h",
         "src/core/lib/slice/slice_internal.h",
         "src/core/lib/slice/slice_string_helpers.h",
+        "src/core/lib/slice/slice_utils.h",
         "src/core/lib/slice/slice_weak_hash_table.h",
         "src/core/lib/surface/api_trace.h",
         "src/core/lib/surface/call.h",
@@ -1028,7 +1033,7 @@ grpc_cc_library(
         "src/core/lib/uri/uri_parser.h",
     ],
     external_deps = [
-        "zlib",
+        "madler_zlib",
     ],
     language = "c++",
     public_hdrs = GRPC_PUBLIC_HDRS,
@@ -1138,6 +1143,7 @@ grpc_cc_library(
         "src/core/ext/filters/client_channel/server_address.h",
         "src/core/ext/filters/client_channel/service_config.h",
         "src/core/ext/filters/client_channel/subchannel.h",
+        "src/core/ext/filters/client_channel/subchannel_interface.h",
         "src/core/ext/filters/client_channel/subchannel_pool_interface.h",
     ],
     language = "c++",
@@ -2158,6 +2164,7 @@ grpc_cc_library(
         "include/grpcpp/impl/codegen/channel_interface.h",
         "include/grpcpp/impl/codegen/client_callback.h",
         "include/grpcpp/impl/codegen/client_context.h",
+        "include/grpcpp/impl/codegen/client_context_impl.h",
         "include/grpcpp/impl/codegen/client_interceptor.h",
         "include/grpcpp/impl/codegen/client_unary_call.h",
         "include/grpcpp/impl/codegen/completion_queue.h",
@@ -2179,6 +2186,7 @@ grpc_cc_library(
         "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_context_impl.h",
         "include/grpcpp/impl/codegen/server_interceptor.h",
         "include/grpcpp/impl/codegen/server_interface.h",
         "include/grpcpp/impl/codegen/service_type.h",
index d3c1186..e5396f5 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -345,6 +345,7 @@ config("grpc_config") {
         "src/core/ext/filters/client_channel/service_config.h",
         "src/core/ext/filters/client_channel/subchannel.cc",
         "src/core/ext/filters/client_channel/subchannel.h",
+        "src/core/ext/filters/client_channel/subchannel_interface.h",
         "src/core/ext/filters/client_channel/subchannel_pool_interface.cc",
         "src/core/ext/filters/client_channel/subchannel_pool_interface.h",
         "src/core/ext/filters/deadline/deadline_filter.cc",
@@ -737,6 +738,7 @@ config("grpc_config") {
         "src/core/lib/slice/slice_internal.h",
         "src/core/lib/slice/slice_string_helpers.cc",
         "src/core/lib/slice/slice_string_helpers.h",
+        "src/core/lib/slice/slice_utils.h",
         "src/core/lib/slice/slice_weak_hash_table.h",
         "src/core/lib/surface/api_trace.cc",
         "src/core/lib/surface/api_trace.h",
@@ -1052,6 +1054,7 @@ config("grpc_config") {
         "include/grpcpp/impl/codegen/channel_interface.h",
         "include/grpcpp/impl/codegen/client_callback.h",
         "include/grpcpp/impl/codegen/client_context.h",
+        "include/grpcpp/impl/codegen/client_context_impl.h",
         "include/grpcpp/impl/codegen/client_interceptor.h",
         "include/grpcpp/impl/codegen/client_unary_call.h",
         "include/grpcpp/impl/codegen/completion_queue.h",
@@ -1079,6 +1082,7 @@ config("grpc_config") {
         "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_context_impl.h",
         "include/grpcpp/impl/codegen/server_interceptor.h",
         "include/grpcpp/impl/codegen/server_interface.h",
         "include/grpcpp/impl/codegen/service_type.h",
@@ -1138,6 +1142,7 @@ config("grpc_config") {
         "include/grpcpp/support/stub_options.h",
         "include/grpcpp/support/sync_stream.h",
         "include/grpcpp/support/time.h",
+        "include/grpcpp/support/validate_service_config.h",
         "src/core/ext/transport/inproc/inproc_transport.h",
         "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.h",
@@ -1281,6 +1286,7 @@ config("grpc_config") {
         "src/core/lib/slice/slice_hash_table.h",
         "src/core/lib/slice/slice_internal.h",
         "src/core/lib/slice/slice_string_helpers.h",
+        "src/core/lib/slice/slice_utils.h",
         "src/core/lib/slice/slice_weak_hash_table.h",
         "src/core/lib/surface/api_trace.h",
         "src/core/lib/surface/call.h",
@@ -1336,12 +1342,15 @@ config("grpc_config") {
         "src/cpp/common/secure_auth_context.h",
         "src/cpp/common/secure_channel_arguments.cc",
         "src/cpp/common/secure_create_auth_context.cc",
+        "src/cpp/common/validate_service_config.cc",
         "src/cpp/common/version_cc.cc",
         "src/cpp/server/async_generic_service.cc",
         "src/cpp/server/channel_argument_option.cc",
         "src/cpp/server/create_default_thread_pool.cc",
         "src/cpp/server/dynamic_thread_pool.cc",
         "src/cpp/server/dynamic_thread_pool.h",
+        "src/cpp/server/external_connection_acceptor_impl.cc",
+        "src/cpp/server/external_connection_acceptor_impl.h",
         "src/cpp/server/health/default_health_check_service.cc",
         "src/cpp/server/health/default_health_check_service.h",
         "src/cpp/server/health/health_check_service.cc",
index 1f01e79..5b330d4 100644 (file)
@@ -24,7 +24,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.21.3")
+set(PACKAGE_VERSION   "1.22.0")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -82,6 +82,8 @@ if(UNIX)
     set(_gRPC_PLATFORM_LINUX ON)
   elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
     set(_gRPC_PLATFORM_MAC ON)
+  elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS")
+    set(_gRPC_PLATFORM_IOS ON)
   elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
     set(_gRPC_PLATFORM_ANDROID ON)
   else()
@@ -124,7 +126,7 @@ if(gRPC_BACKWARDS_COMPATIBILITY_MODE)
   endif()
 endif()
 
-if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
+if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
   # C core has C++ source code, but should not depend on libstc++ (for better portability).
   # We need to use a few tricks to convince cmake to do that.
   # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc
@@ -149,7 +151,7 @@ if(NOT MSVC)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
 endif()
 
-if(_gRPC_PLATFORM_MAC)
+if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m pthread)
 elseif(_gRPC_PLATFORM_ANDROID)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m)
@@ -438,17 +440,6 @@ add_dependencies(buildtests_c udp_server_test)
 endif()
 add_dependencies(buildtests_c uri_parser_test)
 add_dependencies(buildtests_c public_headers_must_be_c89)
-add_dependencies(buildtests_c badreq_bad_client_test)
-add_dependencies(buildtests_c connection_prefix_bad_client_test)
-add_dependencies(buildtests_c duplicate_header_bad_client_test)
-add_dependencies(buildtests_c head_of_line_blocking_bad_client_test)
-add_dependencies(buildtests_c headers_bad_client_test)
-add_dependencies(buildtests_c initial_settings_frame_bad_client_test)
-add_dependencies(buildtests_c large_metadata_bad_client_test)
-add_dependencies(buildtests_c server_registered_method_bad_client_test)
-add_dependencies(buildtests_c simple_request_bad_client_test)
-add_dependencies(buildtests_c unknown_frame_bad_client_test)
-add_dependencies(buildtests_c window_overflow_bad_client_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_c bad_ssl_cert_server)
 endif()
@@ -556,6 +547,12 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_call_create)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx bm_callback_streaming_ping_pong)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx bm_callback_unary_ping_pong)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_channel)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -670,6 +667,7 @@ add_dependencies(buildtests_cxx nonblocking_test)
 add_dependencies(buildtests_cxx noop-benchmark)
 add_dependencies(buildtests_cxx optional_test)
 add_dependencies(buildtests_cxx orphanable_test)
+add_dependencies(buildtests_cxx port_sharing_end2end_test)
 add_dependencies(buildtests_cxx proto_server_reflection_test)
 add_dependencies(buildtests_cxx proto_utils_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -726,6 +724,17 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx writes_per_rpc_test)
 endif()
 add_dependencies(buildtests_cxx xds_end2end_test)
+add_dependencies(buildtests_cxx badreq_bad_client_test)
+add_dependencies(buildtests_cxx connection_prefix_bad_client_test)
+add_dependencies(buildtests_cxx duplicate_header_bad_client_test)
+add_dependencies(buildtests_cxx head_of_line_blocking_bad_client_test)
+add_dependencies(buildtests_cxx headers_bad_client_test)
+add_dependencies(buildtests_cxx initial_settings_frame_bad_client_test)
+add_dependencies(buildtests_cxx large_metadata_bad_client_test)
+add_dependencies(buildtests_cxx server_registered_method_bad_client_test)
+add_dependencies(buildtests_cxx simple_request_bad_client_test)
+add_dependencies(buildtests_cxx unknown_frame_bad_client_test)
+add_dependencies(buildtests_cxx window_overflow_bad_client_test)
 add_dependencies(buildtests_cxx resolver_component_test_unsecure)
 add_dependencies(buildtests_cxx resolver_component_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -2909,6 +2918,67 @@ target_link_libraries(test_tcp_server
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
+add_library(bm_callback_test_service_impl
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_mock.grpc.pb.h
+  test/cpp/microbenchmarks/callback_test_service.cc
+)
+
+if(WIN32 AND MSVC)
+  set_target_properties(bm_callback_test_service_impl PROPERTIES COMPILE_PDB_NAME "bm_callback_test_service_impl"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+  )
+  if (gRPC_INSTALL)
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bm_callback_test_service_impl.pdb
+      DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL
+    )
+  endif()
+endif()
+
+protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/echo.proto
+)
+
+target_include_directories(bm_callback_test_service_impl
+  PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  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(bm_callback_test_service_impl
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_benchmark
+  ${_gRPC_BENCHMARK_LIBRARIES}
+  grpc++_test_util_unsecure
+  grpc_test_util_unsecure
+  grpc++_unsecure
+  grpc_unsecure
+  gpr
+  grpc++_test_config
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_CODEGEN)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_library(dns_test_util
   test/cpp/naming/dns_test_util.cc
 )
@@ -2975,11 +3045,13 @@ add_library(grpc++
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/validate_service_config.cc
   src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/channel_argument_option.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
+  src/cpp/server/external_connection_acceptor_impl.cc
   src/cpp/server/health/default_health_check_service.cc
   src/cpp/server/health/health_check_service.cc
   src/cpp/server/health/health_check_service_server_builder_option.cc
@@ -3149,6 +3221,7 @@ foreach(_hdr
   include/grpcpp/support/stub_options.h
   include/grpcpp/support/sync_stream.h
   include/grpcpp/support/time.h
+  include/grpcpp/support/validate_service_config.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
@@ -3242,6 +3315,7 @@ foreach(_hdr
   include/grpcpp/impl/codegen/channel_interface.h
   include/grpcpp/impl/codegen/client_callback.h
   include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_context_impl.h
   include/grpcpp/impl/codegen/client_interceptor.h
   include/grpcpp/impl/codegen/client_unary_call.h
   include/grpcpp/impl/codegen/completion_queue.h
@@ -3263,6 +3337,7 @@ foreach(_hdr
   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_context_impl.h
   include/grpcpp/impl/codegen/server_interceptor.h
   include/grpcpp/impl/codegen/server_interface.h
   include/grpcpp/impl/codegen/service_type.h
@@ -3371,11 +3446,13 @@ add_library(grpc++_cronet
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/validate_service_config.cc
   src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/channel_argument_option.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
+  src/cpp/server/external_connection_acceptor_impl.cc
   src/cpp/server/health/default_health_check_service.cc
   src/cpp/server/health/health_check_service.cc
   src/cpp/server/health/health_check_service_server_builder_option.cc
@@ -3765,6 +3842,7 @@ foreach(_hdr
   include/grpcpp/support/stub_options.h
   include/grpcpp/support/sync_stream.h
   include/grpcpp/support/time.h
+  include/grpcpp/support/validate_service_config.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
@@ -3858,6 +3936,7 @@ foreach(_hdr
   include/grpcpp/impl/codegen/channel_interface.h
   include/grpcpp/impl/codegen/client_callback.h
   include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_context_impl.h
   include/grpcpp/impl/codegen/client_interceptor.h
   include/grpcpp/impl/codegen/client_unary_call.h
   include/grpcpp/impl/codegen/completion_queue.h
@@ -3879,6 +3958,7 @@ foreach(_hdr
   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_context_impl.h
   include/grpcpp/impl/codegen/server_interceptor.h
   include/grpcpp/impl/codegen/server_interface.h
   include/grpcpp/impl/codegen/service_type.h
@@ -4293,6 +4373,7 @@ foreach(_hdr
   include/grpcpp/impl/codegen/channel_interface.h
   include/grpcpp/impl/codegen/client_callback.h
   include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_context_impl.h
   include/grpcpp/impl/codegen/client_interceptor.h
   include/grpcpp/impl/codegen/client_unary_call.h
   include/grpcpp/impl/codegen/completion_queue.h
@@ -4314,6 +4395,7 @@ foreach(_hdr
   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_context_impl.h
   include/grpcpp/impl/codegen/server_interceptor.h
   include/grpcpp/impl/codegen/server_interface.h
   include/grpcpp/impl/codegen/service_type.h
@@ -4492,6 +4574,7 @@ foreach(_hdr
   include/grpcpp/impl/codegen/channel_interface.h
   include/grpcpp/impl/codegen/client_callback.h
   include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_context_impl.h
   include/grpcpp/impl/codegen/client_interceptor.h
   include/grpcpp/impl/codegen/client_unary_call.h
   include/grpcpp/impl/codegen/completion_queue.h
@@ -4513,6 +4596,7 @@ foreach(_hdr
   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_context_impl.h
   include/grpcpp/impl/codegen/server_interceptor.h
   include/grpcpp/impl/codegen/server_interface.h
   include/grpcpp/impl/codegen/service_type.h
@@ -4582,11 +4666,13 @@ add_library(grpc++_unsecure
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/validate_service_config.cc
   src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/channel_argument_option.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
+  src/cpp/server/external_connection_acceptor_impl.cc
   src/cpp/server/health/default_health_check_service.cc
   src/cpp/server/health/health_check_service.cc
   src/cpp/server/health/health_check_service_server_builder_option.cc
@@ -4755,6 +4841,7 @@ foreach(_hdr
   include/grpcpp/support/stub_options.h
   include/grpcpp/support/sync_stream.h
   include/grpcpp/support/time.h
+  include/grpcpp/support/validate_service_config.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
@@ -4848,6 +4935,7 @@ foreach(_hdr
   include/grpcpp/impl/codegen/channel_interface.h
   include/grpcpp/impl/codegen/client_callback.h
   include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_context_impl.h
   include/grpcpp/impl/codegen/client_interceptor.h
   include/grpcpp/impl/codegen/client_unary_call.h
   include/grpcpp/impl/codegen/completion_queue.h
@@ -4869,6 +4957,7 @@ foreach(_hdr
   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_context_impl.h
   include/grpcpp/impl/codegen/server_interceptor.h
   include/grpcpp/impl/codegen/server_interface.h
   include/grpcpp/impl/codegen/service_type.h
@@ -5677,58 +5766,6 @@ endif()
 endif (gRPC_BUILD_CSHARP_EXT)
 if (gRPC_BUILD_TESTS)
 
-add_library(upb
-  third_party/upb/google/protobuf/descriptor.upb.c
-  third_party/upb/upb/decode.c
-  third_party/upb/upb/def.c
-  third_party/upb/upb/encode.c
-  third_party/upb/upb/handlers.c
-  third_party/upb/upb/msg.c
-  third_party/upb/upb/msgfactory.c
-  third_party/upb/upb/sink.c
-  third_party/upb/upb/table.c
-  third_party/upb/upb/upb.c
-)
-
-if(WIN32 AND MSVC)
-  set_target_properties(upb PROPERTIES COMPILE_PDB_NAME "upb"
-    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
-  )
-  if (gRPC_INSTALL)
-    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/upb.pdb
-      DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL
-    )
-  endif()
-endif()
-
-
-target_include_directories(upb
-  PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  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}
-)
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(upb PROPERTIES LINKER_LANGUAGE C)
-    # only use the flags for C++ source files
-    target_compile_options(upb PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
-target_link_libraries(upb
-  ${_gRPC_SSL_LIBRARIES}
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-)
-
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_library(bad_client_test
   test/core/bad_client/bad_client.cc
 )
@@ -5756,18 +5793,19 @@ target_include_directories(bad_client_test
   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}
 )
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    # only use the flags for C++ source files
-    target_compile_options(bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 target_link_libraries(bad_client_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
 
@@ -11554,6 +11592,98 @@ endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
+add_executable(bm_callback_streaming_ping_pong
+  test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(bm_callback_streaming_ping_pong
+  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(bm_callback_streaming_ping_pong
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_benchmark
+  ${_gRPC_BENCHMARK_LIBRARIES}
+  grpc++_test_util_unsecure
+  grpc_test_util_unsecure
+  grpc++_unsecure
+  grpc_unsecure
+  gpr
+  grpc++_test_config
+  bm_callback_test_service_impl
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+add_executable(bm_callback_unary_ping_pong
+  test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(bm_callback_unary_ping_pong
+  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(bm_callback_unary_ping_pong
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_benchmark
+  ${_gRPC_BENCHMARK_LIBRARIES}
+  grpc++_test_util_unsecure
+  grpc_test_util_unsecure
+  grpc++_unsecure
+  grpc_unsecure
+  gpr
+  grpc++_test_config
+  bm_callback_test_service_impl
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
 add_executable(bm_channel
   test/cpp/microbenchmarks/bm_channel.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -14969,6 +15099,47 @@ target_link_libraries(orphanable_test
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(port_sharing_end2end_test
+  test/cpp/end2end/port_sharing_end2end_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(port_sharing_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(port_sharing_end2end_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  test_tcp_server
+  grpc++_test_util
+  grpc_test_util
+  grpc++
+  grpc
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(proto_server_reflection_test
   test/cpp/end2end/proto_server_reflection_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -16809,6 +16980,8 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(badreq_bad_client_test
   test/core/bad_client/tests/badreq.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -16823,28 +16996,32 @@ target_include_directories(badreq_bad_client_test
   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(badreq_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(badreq_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(badreq_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(connection_prefix_bad_client_test
   test/core/bad_client/tests/connection_prefix.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -16859,28 +17036,32 @@ target_include_directories(connection_prefix_bad_client_test
   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(connection_prefix_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(connection_prefix_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(connection_prefix_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(duplicate_header_bad_client_test
   test/core/bad_client/tests/duplicate_header.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -16895,28 +17076,32 @@ target_include_directories(duplicate_header_bad_client_test
   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(duplicate_header_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(duplicate_header_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(duplicate_header_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(head_of_line_blocking_bad_client_test
   test/core/bad_client/tests/head_of_line_blocking.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -16931,28 +17116,32 @@ target_include_directories(head_of_line_blocking_bad_client_test
   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(head_of_line_blocking_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(head_of_line_blocking_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(head_of_line_blocking_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(headers_bad_client_test
   test/core/bad_client/tests/headers.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -16967,28 +17156,32 @@ target_include_directories(headers_bad_client_test
   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(headers_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(headers_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(headers_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(initial_settings_frame_bad_client_test
   test/core/bad_client/tests/initial_settings_frame.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17003,28 +17196,32 @@ target_include_directories(initial_settings_frame_bad_client_test
   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(initial_settings_frame_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(initial_settings_frame_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(initial_settings_frame_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(large_metadata_bad_client_test
   test/core/bad_client/tests/large_metadata.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17039,28 +17236,32 @@ target_include_directories(large_metadata_bad_client_test
   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(large_metadata_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(large_metadata_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(large_metadata_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(server_registered_method_bad_client_test
   test/core/bad_client/tests/server_registered_method.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17075,28 +17276,32 @@ target_include_directories(server_registered_method_bad_client_test
   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_registered_method_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(server_registered_method_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(server_registered_method_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(simple_request_bad_client_test
   test/core/bad_client/tests/simple_request.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17111,28 +17316,32 @@ target_include_directories(simple_request_bad_client_test
   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(simple_request_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(simple_request_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(simple_request_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(unknown_frame_bad_client_test
   test/core/bad_client/tests/unknown_frame.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17147,28 +17356,32 @@ target_include_directories(unknown_frame_bad_client_test
   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(unknown_frame_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(unknown_frame_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(unknown_frame_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(window_overflow_bad_client_test
   test/core/bad_client/tests/window_overflow.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
@@ -17183,22 +17396,24 @@ target_include_directories(window_overflow_bad_client_test
   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(window_overflow_bad_client_test
   ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   bad_client_test
   grpc_test_util_unsecure
   grpc_unsecure
   gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
 )
 
-  # avoid dependency on libstdc++
-  if (_gRPC_CORE_NOSTDCXX_FLAGS)
-    set_target_properties(window_overflow_bad_client_test PROPERTIES LINKER_LANGUAGE C)
-    target_compile_options(window_overflow_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
-  endif()
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
index fd29aa3..d80d72b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -460,8 +460,8 @@ Q = @
 endif
 
 CORE_VERSION = 7.0.0
-CPP_VERSION = 1.21.3
-CSHARP_VERSION = 1.21.3
+CPP_VERSION = 1.22.0
+CSHARP_VERSION = 1.22.0
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -1162,6 +1162,8 @@ bm_alarm: $(BINDIR)/$(CONFIG)/bm_alarm
 bm_arena: $(BINDIR)/$(CONFIG)/bm_arena
 bm_byte_buffer: $(BINDIR)/$(CONFIG)/bm_byte_buffer
 bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create
+bm_callback_streaming_ping_pong: $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong
+bm_callback_unary_ping_pong: $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong
 bm_channel: $(BINDIR)/$(CONFIG)/bm_channel
 bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
 bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport
@@ -1242,6 +1244,7 @@ nonblocking_test: $(BINDIR)/$(CONFIG)/nonblocking_test
 noop-benchmark: $(BINDIR)/$(CONFIG)/noop-benchmark
 optional_test: $(BINDIR)/$(CONFIG)/optional_test
 orphanable_test: $(BINDIR)/$(CONFIG)/orphanable_test
+port_sharing_end2end_test: $(BINDIR)/$(CONFIG)/port_sharing_end2end_test
 proto_server_reflection_test: $(BINDIR)/$(CONFIG)/proto_server_reflection_test
 proto_utils_test: $(BINDIR)/$(CONFIG)/proto_utils_test
 qps_interarrival_test: $(BINDIR)/$(CONFIG)/qps_interarrival_test
@@ -1402,7 +1405,7 @@ plugins: $(PROTOC_PLUGINS)
 
 privatelibs: privatelibs_c privatelibs_cxx
 
-privatelibs_c:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libupb.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
+privatelibs_c:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libupb.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
 pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
@@ -1412,9 +1415,9 @@ pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 ifeq ($(EMBED_OPENSSL),true)
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a
 else
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a
 endif
 
 
@@ -1552,17 +1555,6 @@ buildtests_c: privatelibs_c \
   $(BINDIR)/$(CONFIG)/udp_server_test \
   $(BINDIR)/$(CONFIG)/uri_parser_test \
   $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
-  $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
-  $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
-  $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test \
-  $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
-  $(BINDIR)/$(CONFIG)/headers_bad_client_test \
-  $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
-  $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test \
-  $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \
-  $(BINDIR)/$(CONFIG)/simple_request_bad_client_test \
-  $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
-  $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test \
   $(BINDIR)/$(CONFIG)/bad_ssl_cert_server \
   $(BINDIR)/$(CONFIG)/bad_ssl_cert_test \
   $(BINDIR)/$(CONFIG)/h2_census_test \
@@ -1641,6 +1633,8 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/bm_arena \
   $(BINDIR)/$(CONFIG)/bm_byte_buffer \
   $(BINDIR)/$(CONFIG)/bm_call_create \
+  $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong \
+  $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_channel \
   $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
@@ -1714,6 +1708,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/noop-benchmark \
   $(BINDIR)/$(CONFIG)/optional_test \
   $(BINDIR)/$(CONFIG)/orphanable_test \
+  $(BINDIR)/$(CONFIG)/port_sharing_end2end_test \
   $(BINDIR)/$(CONFIG)/proto_server_reflection_test \
   $(BINDIR)/$(CONFIG)/proto_utils_test \
   $(BINDIR)/$(CONFIG)/qps_interarrival_test \
@@ -1756,6 +1751,17 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/xds_end2end_test \
   $(BINDIR)/$(CONFIG)/boringssl_ssl_test \
   $(BINDIR)/$(CONFIG)/boringssl_crypto_test \
+  $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
+  $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
+  $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test \
+  $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
+  $(BINDIR)/$(CONFIG)/headers_bad_client_test \
+  $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
+  $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test \
+  $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \
+  $(BINDIR)/$(CONFIG)/simple_request_bad_client_test \
+  $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
+  $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test \
   $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_test \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure \
@@ -1788,6 +1794,8 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/bm_arena \
   $(BINDIR)/$(CONFIG)/bm_byte_buffer \
   $(BINDIR)/$(CONFIG)/bm_call_create \
+  $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong \
+  $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_channel \
   $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
@@ -1861,6 +1869,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/noop-benchmark \
   $(BINDIR)/$(CONFIG)/optional_test \
   $(BINDIR)/$(CONFIG)/orphanable_test \
+  $(BINDIR)/$(CONFIG)/port_sharing_end2end_test \
   $(BINDIR)/$(CONFIG)/proto_server_reflection_test \
   $(BINDIR)/$(CONFIG)/proto_utils_test \
   $(BINDIR)/$(CONFIG)/qps_interarrival_test \
@@ -1901,6 +1910,17 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/transport_security_common_api_test \
   $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
   $(BINDIR)/$(CONFIG)/xds_end2end_test \
+  $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
+  $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
+  $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test \
+  $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
+  $(BINDIR)/$(CONFIG)/headers_bad_client_test \
+  $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
+  $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test \
+  $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \
+  $(BINDIR)/$(CONFIG)/simple_request_bad_client_test \
+  $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
+  $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test \
   $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_test \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure \
@@ -2167,28 +2187,6 @@ test_c: buildtests_c
        $(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 )
        $(E) "[RUN]     Testing public_headers_must_be_c89"
        $(Q) $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 || ( echo test public_headers_must_be_c89 failed ; exit 1 )
-       $(E) "[RUN]     Testing badreq_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/badreq_bad_client_test || ( echo test badreq_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing connection_prefix_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test || ( echo test connection_prefix_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing duplicate_header_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test || ( echo test duplicate_header_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing head_of_line_blocking_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test || ( echo test head_of_line_blocking_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing headers_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing initial_settings_frame_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing large_metadata_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test || ( echo test large_metadata_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing server_registered_method_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing simple_request_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/simple_request_bad_client_test || ( echo test simple_request_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing unknown_frame_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test || ( echo test unknown_frame_bad_client_test failed ; exit 1 )
-       $(E) "[RUN]     Testing window_overflow_bad_client_test"
-       $(Q) $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test || ( echo test window_overflow_bad_client_test failed ; exit 1 )
        $(E) "[RUN]     Testing bad_ssl_cert_test"
        $(Q) $(BINDIR)/$(CONFIG)/bad_ssl_cert_test || ( echo test bad_ssl_cert_test failed ; exit 1 )
 
@@ -2241,6 +2239,10 @@ test_cxx: buildtests_cxx
        $(Q) $(BINDIR)/$(CONFIG)/bm_byte_buffer || ( echo test bm_byte_buffer failed ; exit 1 )
        $(E) "[RUN]     Testing bm_call_create"
        $(Q) $(BINDIR)/$(CONFIG)/bm_call_create || ( echo test bm_call_create failed ; exit 1 )
+       $(E) "[RUN]     Testing bm_callback_streaming_ping_pong"
+       $(Q) $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong || ( echo test bm_callback_streaming_ping_pong failed ; exit 1 )
+       $(E) "[RUN]     Testing bm_callback_unary_ping_pong"
+       $(Q) $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong || ( echo test bm_callback_unary_ping_pong failed ; exit 1 )
        $(E) "[RUN]     Testing bm_channel"
        $(Q) $(BINDIR)/$(CONFIG)/bm_channel || ( echo test bm_channel failed ; exit 1 )
        $(E) "[RUN]     Testing bm_chttp2_hpack"
@@ -2371,6 +2373,8 @@ test_cxx: buildtests_cxx
        $(Q) $(BINDIR)/$(CONFIG)/optional_test || ( echo test optional_test failed ; exit 1 )
        $(E) "[RUN]     Testing orphanable_test"
        $(Q) $(BINDIR)/$(CONFIG)/orphanable_test || ( echo test orphanable_test failed ; exit 1 )
+       $(E) "[RUN]     Testing port_sharing_end2end_test"
+       $(Q) $(BINDIR)/$(CONFIG)/port_sharing_end2end_test || ( echo test port_sharing_end2end_test failed ; exit 1 )
        $(E) "[RUN]     Testing proto_server_reflection_test"
        $(Q) $(BINDIR)/$(CONFIG)/proto_server_reflection_test || ( echo test proto_server_reflection_test failed ; exit 1 )
        $(E) "[RUN]     Testing proto_utils_test"
@@ -2437,6 +2441,28 @@ test_cxx: buildtests_cxx
        $(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
        $(E) "[RUN]     Testing xds_end2end_test"
        $(Q) $(BINDIR)/$(CONFIG)/xds_end2end_test || ( echo test xds_end2end_test failed ; exit 1 )
+       $(E) "[RUN]     Testing badreq_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/badreq_bad_client_test || ( echo test badreq_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing connection_prefix_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test || ( echo test connection_prefix_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing duplicate_header_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test || ( echo test duplicate_header_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing head_of_line_blocking_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test || ( echo test head_of_line_blocking_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing headers_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing initial_settings_frame_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing large_metadata_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test || ( echo test large_metadata_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing server_registered_method_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing simple_request_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/simple_request_bad_client_test || ( echo test simple_request_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing unknown_frame_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test || ( echo test unknown_frame_bad_client_test failed ; exit 1 )
+       $(E) "[RUN]     Testing window_overflow_bad_client_test"
+       $(Q) $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test || ( echo test window_overflow_bad_client_test failed ; exit 1 )
        $(E) "[RUN]     Testing resolver_component_tests_runner_invoker_unsecure"
        $(Q) $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure || ( echo test resolver_component_tests_runner_invoker_unsecure failed ; exit 1 )
        $(E) "[RUN]     Testing resolver_component_tests_runner_invoker"
@@ -5295,6 +5321,58 @@ endif
 endif
 
 
+LIBBM_CALLBACK_TEST_SERVICE_IMPL_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
+    test/cpp/microbenchmarks/callback_test_service.cc \
+
+PUBLIC_HEADERS_CXX += \
+
+LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_SRC))))
+
+$(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS) 
+       $(E) "[AR]      Creating $@"
+       $(Q) mkdir -p `dirname $@`
+       $(Q) rm -f $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+       $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+       $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/callback_test_service.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc
+
+
 LIBDNS_TEST_UTIL_SRC = \
     test/cpp/naming/dns_test_util.cc \
 
@@ -5368,11 +5446,13 @@ LIBGRPC++_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/validate_service_config.cc \
     src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/channel_argument_option.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
+    src/cpp/server/external_connection_acceptor_impl.cc \
     src/cpp/server/health/default_health_check_service.cc \
     src/cpp/server/health/health_check_service.cc \
     src/cpp/server/health/health_check_service_server_builder_option.cc \
@@ -5507,6 +5587,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/support/stub_options.h \
     include/grpcpp/support/sync_stream.h \
     include/grpcpp/support/time.h \
+    include/grpcpp/support/validate_service_config.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
@@ -5600,6 +5681,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/impl/codegen/channel_interface.h \
     include/grpcpp/impl/codegen/client_callback.h \
     include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_context_impl.h \
     include/grpcpp/impl/codegen/client_interceptor.h \
     include/grpcpp/impl/codegen/client_unary_call.h \
     include/grpcpp/impl/codegen/completion_queue.h \
@@ -5621,6 +5703,7 @@ PUBLIC_HEADERS_CXX += \
     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_context_impl.h \
     include/grpcpp/impl/codegen/server_interceptor.h \
     include/grpcpp/impl/codegen/server_interface.h \
     include/grpcpp/impl/codegen/service_type.h \
@@ -5773,11 +5856,13 @@ LIBGRPC++_CRONET_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/validate_service_config.cc \
     src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/channel_argument_option.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
+    src/cpp/server/external_connection_acceptor_impl.cc \
     src/cpp/server/health/default_health_check_service.cc \
     src/cpp/server/health/health_check_service.cc \
     src/cpp/server/health/health_check_service_server_builder_option.cc \
@@ -6131,6 +6216,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/support/stub_options.h \
     include/grpcpp/support/sync_stream.h \
     include/grpcpp/support/time.h \
+    include/grpcpp/support/validate_service_config.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
@@ -6224,6 +6310,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/impl/codegen/channel_interface.h \
     include/grpcpp/impl/codegen/client_callback.h \
     include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_context_impl.h \
     include/grpcpp/impl/codegen/client_interceptor.h \
     include/grpcpp/impl/codegen/client_unary_call.h \
     include/grpcpp/impl/codegen/completion_queue.h \
@@ -6245,6 +6332,7 @@ PUBLIC_HEADERS_CXX += \
     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_context_impl.h \
     include/grpcpp/impl/codegen/server_interceptor.h \
     include/grpcpp/impl/codegen/server_interface.h \
     include/grpcpp/impl/codegen/service_type.h \
@@ -6631,6 +6719,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/impl/codegen/channel_interface.h \
     include/grpcpp/impl/codegen/client_callback.h \
     include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_context_impl.h \
     include/grpcpp/impl/codegen/client_interceptor.h \
     include/grpcpp/impl/codegen/client_unary_call.h \
     include/grpcpp/impl/codegen/completion_queue.h \
@@ -6652,6 +6741,7 @@ PUBLIC_HEADERS_CXX += \
     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_context_impl.h \
     include/grpcpp/impl/codegen/server_interceptor.h \
     include/grpcpp/impl/codegen/server_interface.h \
     include/grpcpp/impl/codegen/service_type.h \
@@ -6801,6 +6891,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/impl/codegen/channel_interface.h \
     include/grpcpp/impl/codegen/client_callback.h \
     include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_context_impl.h \
     include/grpcpp/impl/codegen/client_interceptor.h \
     include/grpcpp/impl/codegen/client_unary_call.h \
     include/grpcpp/impl/codegen/completion_queue.h \
@@ -6822,6 +6913,7 @@ PUBLIC_HEADERS_CXX += \
     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_context_impl.h \
     include/grpcpp/impl/codegen/server_interceptor.h \
     include/grpcpp/impl/codegen/server_interface.h \
     include/grpcpp/impl/codegen/service_type.h \
@@ -6931,11 +7023,13 @@ LIBGRPC++_UNSECURE_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/validate_service_config.cc \
     src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/channel_argument_option.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
+    src/cpp/server/external_connection_acceptor_impl.cc \
     src/cpp/server/health/default_health_check_service.cc \
     src/cpp/server/health/health_check_service.cc \
     src/cpp/server/health/health_check_service_server_builder_option.cc \
@@ -7070,6 +7164,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/support/stub_options.h \
     include/grpcpp/support/sync_stream.h \
     include/grpcpp/support/time.h \
+    include/grpcpp/support/validate_service_config.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
@@ -7163,6 +7258,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpcpp/impl/codegen/channel_interface.h \
     include/grpcpp/impl/codegen/client_callback.h \
     include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_context_impl.h \
     include/grpcpp/impl/codegen/client_interceptor.h \
     include/grpcpp/impl/codegen/client_unary_call.h \
     include/grpcpp/impl/codegen/completion_queue.h \
@@ -7184,6 +7280,7 @@ PUBLIC_HEADERS_CXX += \
     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_context_impl.h \
     include/grpcpp/impl/codegen/server_interceptor.h \
     include/grpcpp/impl/codegen/server_interface.h \
     include/grpcpp/impl/codegen/service_type.h \
@@ -8453,7 +8550,7 @@ endif
 LIBBAD_CLIENT_TEST_SRC = \
     test/core/bad_client/bad_client.cc \
 
-PUBLIC_HEADERS_C += \
+PUBLIC_HEADERS_CXX += \
 
 LIBBAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBAD_CLIENT_TEST_SRC))))
 
@@ -8467,8 +8564,16 @@ $(LIBDIR)/$(CONFIG)/libbad_client_test.a: openssl_dep_error
 
 else
 
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libbad_client_test.a: protobuf_dep_error
+
 
-$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBBAD_CLIENT_TEST_OBJS) 
+else
+
+$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBBAD_CLIENT_TEST_OBJS) 
        $(E) "[AR]      Creating $@"
        $(Q) mkdir -p `dirname $@`
        $(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_client_test.a
@@ -8482,6 +8587,8 @@ endif
 
 endif
 
+endif
+
 ifneq ($(NO_SECURE),true)
 ifneq ($(NO_DEPS),true)
 -include $(LIBBAD_CLIENT_TEST_OBJS:.o=.dep)
@@ -14495,6 +14602,94 @@ endif
 endif
 
 
+BM_CALLBACK_STREAMING_PING_PONG_SRC = \
+    test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc \
+
+BM_CALLBACK_STREAMING_PING_PONG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CALLBACK_STREAMING_PING_PONG_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong: 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)/bm_callback_streaming_ping_pong: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong: $(PROTOBUF_DEP) $(BM_CALLBACK_STREAMING_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+       $(E) "[LD]      Linking $@"
+       $(Q) mkdir -p `dirname $@`
+       $(Q) $(LDXX) $(LDFLAGS) $(BM_CALLBACK_STREAMING_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong
+
+endif
+
+endif
+
+$(BM_CALLBACK_STREAMING_PING_PONG_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.o:  $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+
+deps_bm_callback_streaming_ping_pong: $(BM_CALLBACK_STREAMING_PING_PONG_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BM_CALLBACK_STREAMING_PING_PONG_OBJS:.o=.dep)
+endif
+endif
+
+
+BM_CALLBACK_UNARY_PING_PONG_SRC = \
+    test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc \
+
+BM_CALLBACK_UNARY_PING_PONG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CALLBACK_UNARY_PING_PONG_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong: 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)/bm_callback_unary_ping_pong: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong: $(PROTOBUF_DEP) $(BM_CALLBACK_UNARY_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+       $(E) "[LD]      Linking $@"
+       $(Q) mkdir -p `dirname $@`
+       $(Q) $(LDXX) $(LDFLAGS) $(BM_CALLBACK_UNARY_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong
+
+endif
+
+endif
+
+$(BM_CALLBACK_UNARY_PING_PONG_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.o:  $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a
+
+deps_bm_callback_unary_ping_pong: $(BM_CALLBACK_UNARY_PING_PONG_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BM_CALLBACK_UNARY_PING_PONG_OBJS:.o=.dep)
+endif
+endif
+
+
 BM_CHANNEL_SRC = \
     test/cpp/microbenchmarks/bm_channel.cc \
 
@@ -17930,6 +18125,49 @@ endif
 endif
 
 
+PORT_SHARING_END2END_TEST_SRC = \
+    test/cpp/end2end/port_sharing_end2end_test.cc \
+
+PORT_SHARING_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PORT_SHARING_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/port_sharing_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)/port_sharing_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/port_sharing_end2end_test: $(PROTOBUF_DEP) $(PORT_SHARING_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+       $(E) "[LD]      Linking $@"
+       $(Q) mkdir -p `dirname $@`
+       $(Q) $(LDXX) $(LDFLAGS) $(PORT_SHARING_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/port_sharing_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/port_sharing_end2end_test.o:  $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_port_sharing_end2end_test: $(PORT_SHARING_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(PORT_SHARING_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 PROTO_SERVER_REFLECTION_TEST_SRC = \
     test/cpp/end2end/proto_server_reflection_test.cc \
 
@@ -20091,10 +20329,21 @@ BADREQ_BAD_CLIENT_TEST_SRC = \
 BADREQ_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BADREQ_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/badreq_bad_client_test: $(BADREQ_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/badreq_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/badreq_bad_client_test: $(PROTOBUF_DEP) $(BADREQ_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(BADREQ_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/badreq_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(BADREQ_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/badreq_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/badreq.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20111,10 +20360,21 @@ CONNECTION_PREFIX_BAD_CLIENT_TEST_SRC = \
 CONNECTION_PREFIX_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CONNECTION_PREFIX_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test: $(CONNECTION_PREFIX_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/connection_prefix_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test: $(PROTOBUF_DEP) $(CONNECTION_PREFIX_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(CONNECTION_PREFIX_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(CONNECTION_PREFIX_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/connection_prefix.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20131,10 +20391,21 @@ DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC = \
 DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test: $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/duplicate_header_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test: $(PROTOBUF_DEP) $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/duplicate_header.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20151,10 +20422,21 @@ HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_SRC = \
 HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test: $(HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/head_of_line_blocking_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test: $(PROTOBUF_DEP) $(HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/head_of_line_blocking.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20171,10 +20453,21 @@ HEADERS_BAD_CLIENT_TEST_SRC = \
 HEADERS_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HEADERS_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/headers_bad_client_test: $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/headers_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/headers_bad_client_test: $(PROTOBUF_DEP) $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/headers_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/headers_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/headers.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20191,10 +20484,21 @@ INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_SRC = \
 INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test: $(INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/initial_settings_frame_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test: $(PROTOBUF_DEP) $(INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/initial_settings_frame.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20211,10 +20515,21 @@ LARGE_METADATA_BAD_CLIENT_TEST_SRC = \
 LARGE_METADATA_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LARGE_METADATA_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test: $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/large_metadata_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test: $(PROTOBUF_DEP) $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/large_metadata.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20231,10 +20546,21 @@ SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC = \
 SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test: $(SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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_registered_method_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test: $(PROTOBUF_DEP) $(SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/server_registered_method.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20251,10 +20577,21 @@ SIMPLE_REQUEST_BAD_CLIENT_TEST_SRC = \
 SIMPLE_REQUEST_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SIMPLE_REQUEST_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/simple_request_bad_client_test: $(SIMPLE_REQUEST_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/simple_request_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/simple_request_bad_client_test: $(PROTOBUF_DEP) $(SIMPLE_REQUEST_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(SIMPLE_REQUEST_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/simple_request_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(SIMPLE_REQUEST_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/simple_request_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/simple_request.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20271,10 +20608,21 @@ UNKNOWN_FRAME_BAD_CLIENT_TEST_SRC = \
 UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(UNKNOWN_FRAME_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test: $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/unknown_frame_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test: $(PROTOBUF_DEP) $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/unknown_frame.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -20291,10 +20639,21 @@ WINDOW_OVERFLOW_BAD_CLIENT_TEST_SRC = \
 WINDOW_OVERFLOW_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WINDOW_OVERFLOW_BAD_CLIENT_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/window_overflow_bad_client_test: $(WINDOW_OVERFLOW_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+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)/window_overflow_bad_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/window_overflow_bad_client_test: $(PROTOBUF_DEP) $(WINDOW_OVERFLOW_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LD) $(LDFLAGS) $(WINDOW_OVERFLOW_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test
+       $(Q) $(LDXX) $(LDFLAGS) $(WINDOW_OVERFLOW_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/window_overflow_bad_client_test
+
+endif
 
 $(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/window_overflow.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
@@ -22284,6 +22643,7 @@ test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_server.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_server_bootstrap.cc: $(OPENSSL_DEP)
 test/cpp/interop/server_helper.cc: $(OPENSSL_DEP)
+test/cpp/microbenchmarks/callback_test_service.cc: $(OPENSSL_DEP)
 test/cpp/microbenchmarks/helpers.cc: $(OPENSSL_DEP)
 test/cpp/naming/dns_test_util.cc: $(OPENSSL_DEP)
 test/cpp/qps/benchmark_config.cc: $(OPENSSL_DEP)
index d604f79..8123dc5 100755 (executable)
--- a/Rakefile
+++ b/Rakefile
@@ -124,10 +124,10 @@ task 'gem:native' do
         "invoked on macos with ruby #{RUBY_VERSION}. The ruby macos artifact " \
         "build should be running on ruby 2.5."
     end
-    system "rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.0:2.4.0:2.3.0:2.2.2 V=#{verbose} GRPC_CONFIG=#{grpc_config}"
+    system "rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.0:2.4.0:2.3.0 V=#{verbose} GRPC_CONFIG=#{grpc_config}"
   else
     Rake::Task['dlls'].execute
-    docker_for_windows "gem update --system --no-document && bundle && rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.0:2.4.0:2.3.0:2.2.2 V=#{verbose} GRPC_CONFIG=#{grpc_config}"
+    docker_for_windows "gem update --system --no-document && bundle && rake cross native gem RUBY_CC_VERSION=2.6.0:2.5.0:2.4.0:2.3.0 V=#{verbose} GRPC_CONFIG=#{grpc_config}"
   end
 end
 
index 29a888f..b7edcda 100644 (file)
@@ -41,11 +41,11 @@ def _join_directories(directories):
 
 def generate_cc_impl(ctx):
     """Implementation of the generate_cc rule."""
-    protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources]
+    protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources.to_list()]
     includes = [
         f
         for src in ctx.attr.srcs
-        for f in src.proto.transitive_imports
+        for f in src.proto.transitive_imports.to_list()
     ]
     outs = []
     proto_root = get_proto_root(
@@ -128,7 +128,7 @@ def generate_cc_impl(ctx):
             arguments += ["-I{0}".format(f + "/../..")]
             well_known_proto_files = [
                 f
-                for f in ctx.attr.well_known_protos.files
+                for f in ctx.attr.well_known_protos.files.to_list()
             ]
 
     ctx.actions.run(
index a4e6509..151825c 100644 (file)
@@ -32,8 +32,8 @@ def grpc_deps():
     )
 
     native.bind(
-        name = "zlib",
-        actual = "@com_github_madler_zlib//:z",
+        name = "madler_zlib",
+        actual = "@zlib//:zlib",
     )
 
     native.bind(
@@ -115,9 +115,9 @@ def grpc_deps():
             url = "https://boringssl.googlesource.com/boringssl/+archive/afc30d43eef92979b05776ec0963c9cede5fb80f.tar.gz",
         )
 
-    if "com_github_madler_zlib" not in native.existing_rules():
+    if "zlib" not in native.existing_rules():
         http_archive(
-            name = "com_github_madler_zlib",
+            name = "zlib",
             build_file = "@com_github_grpc_grpc//third_party:zlib.BUILD",
             sha256 = "6d4d6640ca3121620995ee255945161821218752b551a1a180f4215f7d124d45",
             strip_prefix = "zlib-cacf7f1d4e3d44d871b605da3b647f07d718623f",
@@ -127,9 +127,9 @@ def grpc_deps():
     if "com_google_protobuf" not in native.existing_rules():
         http_archive(
             name = "com_google_protobuf",
-            sha256 = "cf9e2fb1d2cd30ec9d51ff1749045208bd641f290f64b85046485934b0e03783",
-            strip_prefix = "protobuf-582743bf40c5d3639a70f98f183914a2c0cd0680",
-            url = "https://github.com/google/protobuf/archive/582743bf40c5d3639a70f98f183914a2c0cd0680.tar.gz",
+            sha256 = "416212e14481cff8fd4849b1c1c1200a7f34808a54377e22d7447efdf54ad758",
+            strip_prefix = "protobuf-09745575a923640154bcf307fba8aedff47f240a",
+            url = "https://github.com/google/protobuf/archive/09745575a923640154bcf307fba8aedff47f240a.tar.gz",
         )
 
     if "com_github_nanopb_nanopb" not in native.existing_rules():
@@ -186,11 +186,11 @@ def grpc_deps():
     if "bazel_toolchains" not in native.existing_rules():
         http_archive(
             name = "bazel_toolchains",
-            sha256 = "67335b3563d9b67dc2550b8f27cc689b64fadac491e69ce78763d9ba894cc5cc",
-            strip_prefix = "bazel-toolchains-cddc376d428ada2927ad359211c3e356bd9c9fbb",
+            sha256 = "88e818f9f03628eef609c8429c210ecf265ffe46c2af095f36c7ef8b1855fef5",
+            strip_prefix = "bazel-toolchains-92dd8a7a518a2fb7ba992d47c8b38299fe0be825",
             urls = [
-                "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
-                "https://github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
+                "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
+                "https://github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
             ],
         )
 
index 2f3b38a..17004f3 100644 (file)
@@ -33,7 +33,7 @@ def _generate_py_impl(context):
     includes = [
         file
         for src in context.attr.deps
-        for file in src.proto.transitive_imports
+        for file in src.proto.transitive_imports.to_list()
     ]
     proto_root = get_proto_root(context.label.workspace_root)
     format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT)
index d9a7273..d04ffcf 100644 (file)
@@ -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
-  g_stands_for: gandalf
-  version: 1.21.3
+  g_stands_for: gale
+  version: 1.22.0
 filegroups:
 - name: alts_proto
   headers:
@@ -525,6 +525,7 @@ filegroups:
   - src/core/lib/slice/slice_hash_table.h
   - src/core/lib/slice/slice_internal.h
   - src/core/lib/slice/slice_string_helpers.h
+  - src/core/lib/slice/slice_utils.h
   - src/core/lib/slice/slice_weak_hash_table.h
   - src/core/lib/surface/api_trace.h
   - src/core/lib/surface/call.h
@@ -594,6 +595,7 @@ filegroups:
   - src/core/ext/filters/client_channel/server_address.h
   - src/core/ext/filters/client_channel/service_config.h
   - src/core/ext/filters/client_channel/subchannel.h
+  - src/core/ext/filters/client_channel/subchannel_interface.h
   - src/core/ext/filters/client_channel/subchannel_pool_interface.h
   src:
   - src/core/ext/filters/client_channel/backup_poller.cc
@@ -1258,6 +1260,7 @@ filegroups:
   - include/grpcpp/impl/codegen/channel_interface.h
   - include/grpcpp/impl/codegen/client_callback.h
   - include/grpcpp/impl/codegen/client_context.h
+  - include/grpcpp/impl/codegen/client_context_impl.h
   - include/grpcpp/impl/codegen/client_interceptor.h
   - include/grpcpp/impl/codegen/client_unary_call.h
   - include/grpcpp/impl/codegen/completion_queue.h
@@ -1279,6 +1282,7 @@ filegroups:
   - 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_context_impl.h
   - include/grpcpp/impl/codegen/server_interceptor.h
   - include/grpcpp/impl/codegen/server_interface.h
   - include/grpcpp/impl/codegen/service_type.h
@@ -1425,10 +1429,12 @@ filegroups:
   - include/grpcpp/support/stub_options.h
   - include/grpcpp/support/sync_stream.h
   - include/grpcpp/support/time.h
+  - include/grpcpp/support/validate_service_config.h
   headers:
   - src/cpp/client/create_channel_internal.h
   - src/cpp/common/channel_filter.h
   - src/cpp/server/dynamic_thread_pool.h
+  - src/cpp/server/external_connection_acceptor_impl.h
   - src/cpp/server/health/default_health_check_service.h
   - src/cpp/server/thread_pool_interface.h
   - src/cpp/thread_manager/thread_manager.h
@@ -1448,11 +1454,13 @@ filegroups:
   - src/cpp/common/core_codegen.cc
   - src/cpp/common/resource_quota_cc.cc
   - src/cpp/common/rpc_method.cc
+  - src/cpp/common/validate_service_config.cc
   - src/cpp/common/version_cc.cc
   - src/cpp/server/async_generic_service.cc
   - src/cpp/server/channel_argument_option.cc
   - src/cpp/server/create_default_thread_pool.cc
   - src/cpp/server/dynamic_thread_pool.cc
+  - src/cpp/server/external_connection_acceptor_impl.cc
   - src/cpp/server/health/default_health_check_service.cc
   - src/cpp/server/health/health_check_service.cc
   - src/cpp/server/health/health_check_service_server_builder_option.cc
@@ -1686,6 +1694,24 @@ libs:
   - grpc_test_util
   - grpc
   - gpr
+- name: bm_callback_test_service_impl
+  build: test
+  language: c++
+  headers:
+  - test/cpp/microbenchmarks/callback_test_service.h
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - test/cpp/microbenchmarks/callback_test_service.cc
+  deps:
+  - grpc_benchmark
+  - benchmark
+  - grpc++_test_util_unsecure
+  - grpc_test_util_unsecure
+  - grpc++_unsecure
+  - grpc_unsecure
+  - gpr
+  - grpc++_test_config
+  defaults: benchmark
 - name: dns_test_util
   build: private
   language: c++
@@ -4052,6 +4078,52 @@ targets:
   - linux
   - posix
   uses_polling: false
+- name: bm_callback_streaming_ping_pong
+  build: test
+  language: c++
+  headers:
+  - test/cpp/microbenchmarks/callback_streaming_ping_pong.h
+  src:
+  - test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc
+  deps:
+  - grpc_benchmark
+  - benchmark
+  - grpc++_test_util_unsecure
+  - grpc_test_util_unsecure
+  - grpc++_unsecure
+  - grpc_unsecure
+  - gpr
+  - grpc++_test_config
+  - bm_callback_test_service_impl
+  benchmark: true
+  defaults: benchmark
+  platforms:
+  - mac
+  - linux
+  - posix
+- name: bm_callback_unary_ping_pong
+  build: test
+  language: c++
+  headers:
+  - test/cpp/microbenchmarks/callback_unary_ping_pong.h
+  src:
+  - test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc
+  deps:
+  - grpc_benchmark
+  - benchmark
+  - grpc++_test_util_unsecure
+  - grpc_test_util_unsecure
+  - grpc++_unsecure
+  - grpc_unsecure
+  - gpr
+  - grpc++_test_config
+  - bm_callback_test_service_impl
+  benchmark: true
+  defaults: benchmark
+  platforms:
+  - mac
+  - linux
+  - posix
 - name: bm_channel
   build: test
   language: c++
@@ -5202,6 +5274,19 @@ targets:
   - gpr
   uses:
   - grpc++_test
+- name: port_sharing_end2end_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/cpp/end2end/port_sharing_end2end_test.cc
+  deps:
+  - test_tcp_server
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr
 - name: proto_server_reflection_test
   gtest: true
   build: test
index 778560d..ff6eaba 100644 (file)
@@ -39,7 +39,6 @@ some configuration as environment variables that can be set.
   gRPC C core is processing requests via debug logs. Available tracers include:
   - api - traces api calls to the C core
   - bdp_estimator - traces behavior of bdp estimation logic
-  - call_combiner - traces call combiner state
   - call_error - traces the possible errors contributing to final call status
   - cares_resolver - traces operations of the c-ares based DNS resolver
   - cares_address_sorting - traces operations of the c-ares based DNS
@@ -52,9 +51,6 @@ some configuration as environment variables that can be set.
   - connectivity_state - traces connectivity state changes to channels
   - cronet - traces state in the cronet transport engine
   - executor - traces grpc's internal thread pool ('the executor')
-  - fd_trace - traces fd create(), shutdown() and close() calls for channel fds.
-    Also traces epoll fd create()/close() calls in epollex polling engine
-    traces epoll-fd creation/close calls for epollex polling engine
   - glb - traces the grpclb load balancer
   - handshaker - traces handshaking state
   - health_check_client - traces health checking client code
@@ -74,6 +70,7 @@ some configuration as environment variables that can be set.
   - queue_pluck
   - server_channel - lightweight trace of significant server channel events
   - secure_endpoint - traces bytes flowing through encrypted channels
+  - subchannel - traces the connectivity state of subchannel
   - timer - timers (alarms) in the grpc internals
   - timer_check - more detailed trace of timer logic in grpc internals
   - transport_security - traces metadata about secure channel establishment
@@ -85,10 +82,15 @@ some configuration as environment variables that can be set.
   - alarm_refcount - refcounting traces for grpc_alarm structure
   - metadata - tracks creation and mutation of metadata
   - combiner - traces combiner lock state
+  - call_combiner - traces call combiner state
   - closure - tracks closure creation, scheduling, and completion
+  - fd_trace - traces fd create(), shutdown() and close() calls for channel fds.
+    Also traces epoll fd create()/close() calls in epollex polling engine
+    traces epoll-fd creation/close calls for epollex polling engine
   - pending_tags - traces still-in-progress tags on completion queues
   - polling - traces the selected polling engine
   - polling_api - traces the api calls to polling engine
+  - subchannel_refcount
   - queue_refcount
   - error_refcount
   - stream_refcount
index ba0ba58..6acee77 100644 (file)
@@ -21,3 +21,4 @@
 - 1.19 'g' stands for ['gold'](https://github.com/grpc/grpc/tree/v1.19.x)
 - 1.20 'g' stands for ['godric'](https://github.com/grpc/grpc/tree/v1.20.x)
 - 1.21 'g' stands for ['gandalf'](https://github.com/grpc/grpc/tree/v1.21.x)
+- 1.22 'g' stands for ['gale'](https://github.com/grpc/grpc/tree/v1.22.x)
index 7be8107..22b6e1b 100644 (file)
@@ -43,6 +43,8 @@ message HealthCheckResponse {
 
 service Health {
   rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+
+  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
 }
 ```
 
@@ -68,3 +70,8 @@ matching semantics that both the client and server agree upon.
 A client can declare the server as unhealthy if the rpc is not finished after
 some amount of time. The client should be able to handle the case where server
 does not have the Health service.
+
+A client can call the `Watch` method to perform a streaming health-check.
+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.
index d260237..e425289 100644 (file)
@@ -2,6 +2,7 @@ Server-side API for Authenticating Clients
 ==========================================
 
 NOTE: This document describes how server-side authentication works in C-core based gRPC implementations only. In gRPC Java and Go, server side authentication is handled differently.
+NOTE2: `CallCredentials` class is only valid for secure channels in C-Core. So, for connections under insecure channels, features below might not be avaiable.
 
 ## AuthContext
 
index 6af9234..9af7337 100644 (file)
@@ -21,10 +21,12 @@ CPPFLAGS += `pkg-config --cflags protobuf grpc`
 CXXFLAGS += -std=c++11
 ifeq ($(SYSTEM),Darwin)
 LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
+           -pthread\
            -lgrpc++_reflection\
            -ldl
 else
 LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
+           -pthread\
            -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
            -ldl
 endif
index 48a2073..3bf61cb 100644 (file)
@@ -21,10 +21,12 @@ CPPFLAGS += `pkg-config --cflags protobuf grpc`
 CXXFLAGS += -std=c++11
 ifeq ($(SYSTEM),Darwin)
 LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
+                                        -pthread\
            -lgrpc++_reflection\
            -ldl
 else
 LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
+           -pthread\
            -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
            -ldl
 endif
diff --git a/examples/python/debug/BUILD.bazel b/examples/python/debug/BUILD.bazel
new file mode 100644 (file)
index 0000000..0134d86
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright 2019 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.
+
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+py_binary(
+    name = "debug_server",
+    testonly = 1,
+    srcs = ["debug_server.py"],
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+        "//examples:py_helloworld",
+    ],
+)
+
+py_binary(
+    name = "send_message",
+    testonly = 1,
+    srcs = ["send_message.py"],
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//examples:py_helloworld",
+    ],
+)
+
+py_binary(
+    name = "get_stats",
+    testonly = 1,
+    srcs = ["get_stats.py"],
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+    ],
+)
+
+py_test(
+    name = "_debug_example_test",
+    srcs = ["test/_debug_example_test.py"],
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+        "//examples:py_helloworld",
+        ":debug_server",
+        ":send_message",
+        ":get_stats",
+    ],
+)
\ No newline at end of file
diff --git a/examples/python/debug/README.md b/examples/python/debug/README.md
new file mode 100644 (file)
index 0000000..ceed31e
--- /dev/null
@@ -0,0 +1,68 @@
+# gRPC Python Debug Example
+
+This example demonstrate the usage of Channelz. For a better looking website,
+the [gdebug](https://github.com/grpc/grpc-experiments/tree/master/gdebug) uses
+gRPC-Web protocol and will serve all useful information in web pages.
+
+## Channelz: Live Channel Tracing
+
+Channelz is a channel tracing feature. It will track statistics like how many
+messages have been sent, how many of them failed, what are the connected
+sockets. Since it is implemented in C-Core and has low-overhead, it is
+recommended to turn on for production services. See [Channelz design
+doc](https://github.com/grpc/proposal/blob/master/A14-channelz.md).
+
+## How to enable tracing log
+The tracing log generation might have larger overhead, especially when you try
+to trace transport. It would result in replicating the traffic loads. However,
+it is still the most powerful tool when you need to dive in.
+
+### The Most Verbose Tracing Log
+
+Specify environment variables, then run your application:
+
+```
+GRPC_VERBOSITY=debug
+GRPC_TRACE=all
+```
+
+For more granularity, please see
+[environment_variables](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md).
+
+### Debug Transport Protocol
+
+```
+GRPC_VERBOSITY=debug
+GRPC_TRACE=tcp,http,secure_endpoint,transport_security
+```
+
+### Debug Connection Behavior
+
+```
+GRPC_VERBOSITY=debug
+GRPC_TRACE=call_error,connectivity_state,pick_first,round_robin,glb
+```
+
+## How to debug your application?
+
+`pdb` is a debugging tool that is available for Python interpreters natively.
+You can set breakpoint, and execute commands while the application is stopped.
+
+The simplest usage is add a single line in the place you want to inspect:
+`import pdb; pdb.set_trace()`. When interpreter see this line, it would pop out
+a interactive command line interface for you to inspect the application state.
+
+For more detailed usage, see https://docs.python.org/3/library/pdb.html.
+
+**Caveat**: gRPC Python uses C-Extension under-the-hood, so `pdb` may not be
+able to trace through the whole stack.
+
+## gRPC Command Line Tool
+
+`grpc_cli` is a handy tool to interact with gRPC backend easily. Imageine you can
+inspect what service does a server provide without writing any code, and make
+gRPC calls just like `curl`.
+
+The installation guide: https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md#code-location
+The usage guide: https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md#usage
+The source code: https://github.com/grpc/grpc/blob/master/test/cpp/util/grpc_cli.cc
diff --git a/examples/python/debug/debug_server.py b/examples/python/debug/debug_server.py
new file mode 100644 (file)
index 0000000..64926b5
--- /dev/null
@@ -0,0 +1,90 @@
+# Copyright 2019 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.
+"""The Python example of utilizing Channelz feature."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import argparse
+import logging
+import time
+from concurrent import futures
+import random
+
+import grpc
+from grpc_channelz.v1 import channelz
+
+from examples import helloworld_pb2
+from examples import helloworld_pb2_grpc
+
+_LOGGER = logging.getLogger(__name__)
+_LOGGER.setLevel(logging.INFO)
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+_RANDOM_FAILURE_RATE = 0.3
+
+
+class FaultInjectGreeter(helloworld_pb2_grpc.GreeterServicer):
+
+    def __init__(self, failure_rate):
+        self._failure_rate = failure_rate
+
+    def SayHello(self, request, context):
+        if random.random() < self._failure_rate:
+            context.abort(grpc.StatusCode.UNAVAILABLE,
+                          'Randomly injected failure.')
+        return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
+
+
+def create_server(addr, failure_rate):
+    server = grpc.server(futures.ThreadPoolExecutor())
+    helloworld_pb2_grpc.add_GreeterServicer_to_server(
+        FaultInjectGreeter(failure_rate), server)
+
+    # Add Channelz Servicer to the gRPC server
+    channelz.add_channelz_servicer(server)
+
+    server.add_insecure_port(addr)
+    return server
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--addr',
+        nargs=1,
+        type=str,
+        default='[::]:50051',
+        help='the address to listen on')
+    parser.add_argument(
+        '--failure_rate',
+        nargs=1,
+        type=float,
+        default=0.3,
+        help='a float indicates the percentage of failed message injections')
+    args = parser.parse_args()
+
+    server = create_server(addr=args.addr, failure_rate=args.failure_rate)
+    server.start()
+    try:
+        while True:
+            time.sleep(_ONE_DAY_IN_SECONDS)
+    except KeyboardInterrupt:
+        server.stop(0)
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    main()
diff --git a/examples/python/debug/get_stats.py b/examples/python/debug/get_stats.py
new file mode 100644 (file)
index 0000000..d0b7061
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright 2019 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.
+"""Poll statistics from the server."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import argparse
+import grpc
+from grpc_channelz.v1 import channelz_pb2
+from grpc_channelz.v1 import channelz_pb2_grpc
+
+
+def run(addr):
+    with grpc.insecure_channel(addr) as channel:
+        channelz_stub = channelz_pb2_grpc.ChannelzStub(channel)
+        response = channelz_stub.GetServers(
+            channelz_pb2.GetServersRequest(start_server_id=0))
+        print('Info for all servers: %s' % response)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--addr',
+        nargs=1,
+        type=str,
+        default='[::]:50051',
+        help='the address to request')
+    args = parser.parse_args()
+    run(addr=args.addr)
+
+
+if __name__ == '__main__':
+    logging.basicConfig()
+    main()
diff --git a/examples/python/debug/send_message.py b/examples/python/debug/send_message.py
new file mode 100644 (file)
index 0000000..3bad52c
--- /dev/null
@@ -0,0 +1,64 @@
+# Copyright 2019 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.
+"""Send multiple greeting messages to the backend."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import argparse
+import grpc
+from examples import helloworld_pb2
+from examples import helloworld_pb2_grpc
+
+
+def process(stub, request):
+    try:
+        response = stub.SayHello(request)
+    except grpc.RpcError as rpc_error:
+        print('Received error: %s' % rpc_error)
+    else:
+        print('Received message: %s' % response)
+
+
+def run(addr, n):
+    with grpc.insecure_channel(addr) as channel:
+        stub = helloworld_pb2_grpc.GreeterStub(channel)
+        request = helloworld_pb2.HelloRequest(name='you')
+        for _ in range(n):
+            process(stub, request)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--addr',
+        nargs=1,
+        type=str,
+        default='[::]:50051',
+        help='the address to request')
+    parser.add_argument(
+        '-n',
+        nargs=1,
+        type=int,
+        default=10,
+        help='an integer for number of messages to sent')
+    args = parser.parse_args()
+    run(addr=args.addr, n=args.n)
+
+
+if __name__ == '__main__':
+    logging.basicConfig()
+    main()
diff --git a/examples/python/debug/test/_debug_example_test.py b/examples/python/debug/test/_debug_example_test.py
new file mode 100644 (file)
index 0000000..8983542
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright 2019 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.
+"""Test for gRPC Python debug example."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import unittest
+
+from examples.python.debug import debug_server
+from examples.python.debug import send_message
+from examples.python.debug import get_stats
+
+_LOGGER = logging.getLogger(__name__)
+_LOGGER.setLevel(logging.INFO)
+
+_FAILURE_RATE = 0.5
+_NUMBER_OF_MESSAGES = 100
+
+_ADDR_TEMPLATE = 'localhost:%d'
+
+
+class DebugExampleTest(unittest.TestCase):
+
+    def test_channelz_example(self):
+        server = debug_server.create_server(
+            addr='[::]:0', failure_rate=_FAILURE_RATE)
+        port = server.add_insecure_port('[::]:0')
+        server.start()
+        address = _ADDR_TEMPLATE % port
+
+        send_message.run(addr=address, n=_NUMBER_OF_MESSAGES)
+        get_stats.run(addr=address)
+        server.stop(None)
+        # No unhandled exception raised, test passed!
+
+
+if __name__ == '__main__':
+    logging.basicConfig()
+    unittest.main(verbosity=2)
index 1fdd642..65c4ec5 100644 (file)
@@ -23,7 +23,7 @@
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  # version = '1.21.3'
+  # version = '1.22.0'
   version = '0.0.9'
   s.version  = version
   s.summary  = 'gRPC C++ library'
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
   s.license  = 'Apache License, Version 2.0'
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
-  grpc_version = '1.21.3'
+  grpc_version = '1.22.0'
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
@@ -148,6 +148,7 @@ Pod::Spec.new do |s|
                       'include/grpcpp/support/stub_options.h',
                       'include/grpcpp/support/sync_stream.h',
                       'include/grpcpp/support/time.h',
+                      'include/grpcpp/support/validate_service_config.h',
                       'include/grpcpp/impl/codegen/async_generic_service.h',
                       'include/grpcpp/impl/codegen/async_stream.h',
                       'include/grpcpp/impl/codegen/async_unary_call.h',
@@ -160,6 +161,7 @@ Pod::Spec.new do |s|
                       'include/grpcpp/impl/codegen/channel_interface.h',
                       'include/grpcpp/impl/codegen/client_callback.h',
                       'include/grpcpp/impl/codegen/client_context.h',
+                      'include/grpcpp/impl/codegen/client_context_impl.h',
                       'include/grpcpp/impl/codegen/client_interceptor.h',
                       'include/grpcpp/impl/codegen/client_unary_call.h',
                       'include/grpcpp/impl/codegen/completion_queue.h',
@@ -181,6 +183,7 @@ Pod::Spec.new do |s|
                       '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_context_impl.h',
                       'include/grpcpp/impl/codegen/server_interceptor.h',
                       'include/grpcpp/impl/codegen/server_interface.h',
                       'include/grpcpp/impl/codegen/service_type.h',
@@ -207,6 +210,7 @@ Pod::Spec.new do |s|
                       'src/cpp/client/create_channel_internal.h',
                       'src/cpp/common/channel_filter.h',
                       'src/cpp/server/dynamic_thread_pool.h',
+                      'src/cpp/server/external_connection_acceptor_impl.h',
                       'src/cpp/server/health/default_health_check_service.h',
                       'src/cpp/server/thread_pool_interface.h',
                       'src/cpp/thread_manager/thread_manager.h',
@@ -233,11 +237,13 @@ Pod::Spec.new do |s|
                       'src/cpp/common/core_codegen.cc',
                       'src/cpp/common/resource_quota_cc.cc',
                       'src/cpp/common/rpc_method.cc',
+                      'src/cpp/common/validate_service_config.cc',
                       'src/cpp/common/version_cc.cc',
                       'src/cpp/server/async_generic_service.cc',
                       'src/cpp/server/channel_argument_option.cc',
                       'src/cpp/server/create_default_thread_pool.cc',
                       'src/cpp/server/dynamic_thread_pool.cc',
+                      'src/cpp/server/external_connection_acceptor_impl.cc',
                       'src/cpp/server/health/default_health_check_service.cc',
                       'src/cpp/server/health/health_check_service.cc',
                       'src/cpp/server/health/health_check_service_server_builder_option.cc',
@@ -395,6 +401,7 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/server_address.h',
                       'src/core/ext/filters/client_channel/service_config.h',
                       'src/core/ext/filters/client_channel/subchannel.h',
+                      'src/core/ext/filters/client_channel/subchannel_interface.h',
                       'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
                       'src/core/ext/filters/client_channel/health/health.pb.h',
@@ -518,6 +525,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/slice/slice_hash_table.h',
                       'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
+                      'src/core/lib/slice/slice_utils.h',
                       'src/core/lib/slice/slice_weak_hash_table.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
@@ -576,6 +584,7 @@ Pod::Spec.new do |s|
                               'src/cpp/client/create_channel_internal.h',
                               'src/cpp/common/channel_filter.h',
                               'src/cpp/server/dynamic_thread_pool.h',
+                              'src/cpp/server/external_connection_acceptor_impl.h',
                               'src/cpp/server/health/default_health_check_service.h',
                               'src/cpp/server/thread_pool_interface.h',
                               'src/cpp/thread_manager/thread_manager.h',
@@ -720,6 +729,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/slice/slice_hash_table.h',
                               'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
+                              'src/core/lib/slice/slice_utils.h',
                               'src/core/lib/slice/slice_weak_hash_table.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
index 061d3a2..c7ffda1 100644 (file)
@@ -22,7 +22,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.21.3'
+  version = '1.22.0'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
@@ -371,6 +371,7 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/server_address.h',
                       'src/core/ext/filters/client_channel/service_config.h',
                       'src/core/ext/filters/client_channel/subchannel.h',
+                      'src/core/ext/filters/client_channel/subchannel_interface.h',
                       'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
                       'src/core/ext/filters/client_channel/health/health.pb.h',
@@ -494,6 +495,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/slice/slice_hash_table.h',
                       'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
+                      'src/core/lib/slice/slice_utils.h',
                       'src/core/lib/slice/slice_weak_hash_table.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
@@ -1022,6 +1024,7 @@ Pod::Spec.new do |s|
                               'src/core/ext/filters/client_channel/server_address.h',
                               'src/core/ext/filters/client_channel/service_config.h',
                               'src/core/ext/filters/client_channel/subchannel.h',
+                              'src/core/ext/filters/client_channel/subchannel_interface.h',
                               'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                               'src/core/ext/filters/deadline/deadline_filter.h',
                               'src/core/ext/filters/client_channel/health/health.pb.h',
@@ -1145,6 +1148,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/slice/slice_hash_table.h',
                               'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
+                              'src/core/lib/slice/slice_utils.h',
                               'src/core/lib/slice/slice_weak_hash_table.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
index c38719b..2ebcf2d 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.21.3'
+  version = '1.22.0'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
index 20f9316..cc4d710 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.21.3'
+  version = '1.22.0'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
index e268a8b..4f6e823 100644 (file)
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.21.3'
+  version = '1.22.0'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
index 922f953..32289df 100644 (file)
--- a/grpc.def
+++ b/grpc.def
@@ -101,6 +101,7 @@ EXPORTS
     grpc_google_default_credentials_create
     grpc_set_ssl_roots_override_callback
     grpc_ssl_credentials_create
+    grpc_ssl_credentials_create_ex
     grpc_call_credentials_release
     grpc_composite_channel_credentials_create
     grpc_composite_call_credentials_create
index 5a34687..11469a3 100644 (file)
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
   s.description   = 'Send RPCs from Ruby using GRPC'
   s.license       = 'Apache-2.0'
 
-  s.required_ruby_version = '>= 2.0.0'
+  s.required_ruby_version = '>= 2.3.0'
 
   s.files = %w( Makefile .yardopts )
   s.files += %w( etc/roots.pem )
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
   s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'google-protobuf', '~> 3.7'
+  s.add_dependency 'google-protobuf', '~> 3.8'
   s.add_dependency 'googleapis-common-protos-types', '~> 1.0'
 
   s.add_development_dependency 'bundler',            '~> 1.9'
@@ -305,6 +305,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/filters/client_channel/server_address.h )
   s.files += %w( src/core/ext/filters/client_channel/service_config.h )
   s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
+  s.files += %w( src/core/ext/filters/client_channel/subchannel_interface.h )
   s.files += %w( src/core/ext/filters/client_channel/subchannel_pool_interface.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 )
@@ -428,6 +429,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/slice/slice_hash_table.h )
   s.files += %w( src/core/lib/slice/slice_internal.h )
   s.files += %w( src/core/lib/slice/slice_string_helpers.h )
+  s.files += %w( src/core/lib/slice/slice_utils.h )
   s.files += %w( src/core/lib/slice/slice_weak_hash_table.h )
   s.files += %w( src/core/lib/surface/api_trace.h )
   s.files += %w( src/core/lib/surface/call.h )
index 1cc6e46..6268bed 100644 (file)
--- a/grpc.gyp
+++ b/grpc.gyp
       ],
     },
     {
+      'target_name': 'bm_callback_test_service_impl',
+      'type': 'static_library',
+      'dependencies': [
+        'grpc_benchmark',
+        'benchmark',
+        'grpc++_test_util_unsecure',
+        'grpc_test_util_unsecure',
+        'grpc++_unsecure',
+        'grpc_unsecure',
+        'gpr',
+        'grpc++_test_config',
+      ],
+      'sources': [
+        'src/proto/grpc/testing/echo.proto',
+        'test/cpp/microbenchmarks/callback_test_service.cc',
+      ],
+    },
+    {
       'target_name': 'dns_test_util',
       'type': 'static_library',
       'dependencies': [
         'src/cpp/common/core_codegen.cc',
         'src/cpp/common/resource_quota_cc.cc',
         'src/cpp/common/rpc_method.cc',
+        'src/cpp/common/validate_service_config.cc',
         'src/cpp/common/version_cc.cc',
         'src/cpp/server/async_generic_service.cc',
         'src/cpp/server/channel_argument_option.cc',
         'src/cpp/server/create_default_thread_pool.cc',
         'src/cpp/server/dynamic_thread_pool.cc',
+        'src/cpp/server/external_connection_acceptor_impl.cc',
         'src/cpp/server/health/default_health_check_service.cc',
         'src/cpp/server/health/health_check_service.cc',
         'src/cpp/server/health/health_check_service_server_builder_option.cc',
         'src/cpp/common/core_codegen.cc',
         'src/cpp/common/resource_quota_cc.cc',
         'src/cpp/common/rpc_method.cc',
+        'src/cpp/common/validate_service_config.cc',
         'src/cpp/common/version_cc.cc',
         'src/cpp/server/async_generic_service.cc',
         'src/cpp/server/channel_argument_option.cc',
         'src/cpp/server/create_default_thread_pool.cc',
         'src/cpp/server/dynamic_thread_pool.cc',
+        'src/cpp/server/external_connection_acceptor_impl.cc',
         'src/cpp/server/health/default_health_check_service.cc',
         'src/cpp/server/health/health_check_service.cc',
         'src/cpp/server/health/health_check_service_server_builder_option.cc',
index 5318909..139c0c3 100644 (file)
@@ -163,6 +163,28 @@ typedef struct {
   const char* cert_chain;
 } grpc_ssl_pem_key_cert_pair;
 
+/** Deprecated in favor of grpc_ssl_verify_peer_options. It will be removed
+  after all of its call sites are migrated to grpc_ssl_verify_peer_options.
+  Object that holds additional peer-verification options on a secure
+  channel. */
+typedef struct {
+  /** If non-NULL this callback will be invoked with the expected
+     target_name, the peer's certificate (in PEM format), and whatever
+     userdata pointer is set below. If a non-zero value is returned by this
+     callback then it is treated as a verification failure. Invocation of
+     the callback is blocking, so any implementation should be light-weight.
+     */
+  int (*verify_peer_callback)(const char* target_name, const char* peer_pem,
+                              void* userdata);
+  /** Arbitrary userdata that will be passed as the last argument to
+     verify_peer_callback. */
+  void* verify_peer_callback_userdata;
+  /** A destruct callback that will be invoked when the channel is being
+     cleaned up. The userdata argument will be passed to it. The intent is
+     to perform any cleanup associated with that userdata. */
+  void (*verify_peer_destruct)(void* userdata);
+} verify_peer_options;
+
 /** Object that holds additional peer-verification options on a secure
    channel. */
 typedef struct {
@@ -181,9 +203,11 @@ typedef struct {
      cleaned up. The userdata argument will be passed to it. The intent is
      to perform any cleanup associated with that userdata. */
   void (*verify_peer_destruct)(void* userdata);
-} verify_peer_options;
+} grpc_ssl_verify_peer_options;
 
-/** Creates an SSL credentials object.
+/** Deprecated in favor of grpc_ssl_server_credentials_create_ex. It will be
+   removed after all of its call sites are migrated to
+   grpc_ssl_server_credentials_create_ex. Creates an SSL credentials object.
    - pem_root_certs is the NULL-terminated string containing the PEM encoding
      of the server root certificates. If this parameter is NULL, the
      implementation will first try to dereference the file pointed by the
@@ -214,6 +238,37 @@ GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
     const verify_peer_options* verify_options, void* reserved);
 
+/* Creates an SSL credentials object.
+   - pem_root_certs is the NULL-terminated string containing the PEM encoding
+     of the server root certificates. If this parameter is NULL, the
+     implementation will first try to dereference the file pointed by the
+     GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable, and if that fails,
+     try to get the roots set by grpc_override_ssl_default_roots. Eventually,
+     if all these fail, it will try to get the roots from a well-known place on
+     disk (in the grpc install directory).
+
+     gRPC has implemented root cache if the underlying OpenSSL library supports
+     it. The gRPC root certificates cache is only applicable on the default
+     root certificates, which is used when this parameter is nullptr. If user
+     provides their own pem_root_certs, when creating an SSL credential object,
+     gRPC would not be able to cache it, and each subchannel will generate a
+     copy of the root store. So it is recommended to avoid providing large room
+     pem with pem_root_certs parameter to avoid excessive memory consumption,
+     particularly on mobile platforms such as iOS.
+   - pem_key_cert_pair is a pointer on the object containing client's private
+     key and certificate chain. This parameter can be NULL if the client does
+     not have such a key/cert pair.
+   - verify_options is an optional verify_peer_options object which holds
+     additional options controlling how peer certificates are verified. For
+     example, you can supply a callback which receives the peer's certificate
+     with which you can do additional verification. Can be NULL, in which
+     case verification will retain default behavior. Any settings in
+     verify_options are copied during this call, so the verify_options
+     object can be released afterwards. */
+GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create_ex(
+    const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
+    const grpc_ssl_verify_peer_options* verify_options, void* reserved);
+
 /** --- grpc_call_credentials object.
 
    A call credentials object represents a way to authenticate on a particular
@@ -435,7 +490,7 @@ GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create(
 /** Deprecated in favor of grpc_ssl_server_credentials_create_with_options.
    Same as grpc_ssl_server_credentials_create method except uses
    grpc_ssl_client_certificate_request_type enum to support more ways to
-   authenticate client cerificates.*/
+   authenticate client certificates.*/
 GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create_ex(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,
     size_t num_key_cert_pairs,
@@ -641,7 +696,7 @@ typedef struct grpc_tls_credentials_options grpc_tls_credentials_options;
 
 /** Create an empty TLS credentials options. It is used for
  *  experimental purpose for now and subject to change. */
-GRPCAPI grpc_tls_credentials_options* grpc_tls_credentials_options_create();
+GRPCAPI grpc_tls_credentials_options* grpc_tls_credentials_options_create(void);
 
 /** Set grpc_ssl_client_certificate_request_type field in credentials options
     with the provided type. options should not be NULL.
@@ -683,7 +738,8 @@ GRPCAPI int grpc_tls_credentials_options_set_server_authorization_check_config(
 
 /** Create an empty grpc_tls_key_materials_config instance.
  *  It is used for experimental purpose for now and subject to change. */
-GRPCAPI grpc_tls_key_materials_config* grpc_tls_key_materials_config_create();
+GRPCAPI grpc_tls_key_materials_config* grpc_tls_key_materials_config_create(
+    void);
 
 /** Set grpc_tls_key_materials_config instance with provided a TLS certificate.
     config will take the ownership of pem_root_certs and pem_key_cert_pairs.
index a082f67..1be524a 100644 (file)
@@ -96,7 +96,7 @@ typedef enum {
   /** Server requests client certificate and enforces that the client presents a
      certificate.
 
-     The cerificate presented by the client is verified by the gRPC framework.
+     The certificate presented by the client is verified by the gRPC framework.
      (For a successful connection the client needs to present a certificate that
      can be verified against the root certificate configured by the server)
 
index d7bb545..6daf339 100644 (file)
@@ -48,7 +48,7 @@ typedef struct gpr_timespec {
   int64_t tv_sec;
   int32_t tv_nsec;
   /** Against which clock was this time measured? (or GPR_TIMESPAN if
-      this is a relative time meaure) */
+      this is a relative time measure) */
   gpr_clock_type clock_type;
 } gpr_timespec;
 
index 192a8cf..51fc62b 100644 (file)
@@ -107,7 +107,7 @@ GPRAPI grpc_slice grpc_slice_sub_no_ref(grpc_slice s, size_t begin, size_t end);
 
 /** Splits s into two: modifies s to be s[0:split], and returns a new slice,
    sharing a refcount with s, that contains s[split:s.length].
-   Requires s intialized, split <= s.length */
+   Requires s initialized, split <= s.length */
 GPRAPI grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split);
 
 typedef enum {
@@ -124,7 +124,7 @@ GPRAPI grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* s, size_t split,
 
 /** Splits s into two: modifies s to be s[split:s.length], and returns a new
    slice, sharing a refcount with s, that contains s[0:split].
-   Requires s intialized, split <= s.length */
+   Requires s initialized, split <= s.length */
 GPRAPI grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split);
 
 GPRAPI grpc_slice grpc_empty_slice(void);
index 39917d2..a7eee2b 100644 (file)
@@ -85,7 +85,7 @@ class Channel final : public ::grpc::ChannelInterface,
               interceptor_creators);
 
   ::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method,
-                                    ::grpc::ClientContext* context,
+                                    ::grpc_impl::ClientContext* context,
                                     ::grpc::CompletionQueue* cq) override;
   void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
                         ::grpc::internal::Call* call) override;
@@ -100,8 +100,9 @@ class Channel final : public ::grpc::ChannelInterface,
   ::grpc::CompletionQueue* CallbackCQ() override;
 
   ::grpc::internal::Call CreateCallInternal(
-      const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
-      ::grpc::CompletionQueue* cq, size_t interceptor_pos) override;
+      const ::grpc::internal::RpcMethod& method,
+      ::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq,
+      size_t interceptor_pos) override;
 
   const grpc::string host_;
   grpc_channel* const c_channel_;  // owned
index 7b82f49..e2ba934 100644 (file)
@@ -51,6 +51,7 @@ template <class RequestType, class ResponseType>
 class CallbackServerStreamingHandler;
 template <StatusCode code>
 class ErrorMethodHandler;
+class ExternalConnectionAcceptorImpl;
 template <class R>
 class DeserializeFuncType;
 class GrpcByteBufferPeer;
@@ -185,6 +186,7 @@ class ByteBuffer final {
   friend class ProtoBufferReader;
   friend class ProtoBufferWriter;
   friend class internal::GrpcByteBufferPeer;
+  friend class internal::ExternalConnectionAcceptorImpl;
 
   grpc_byte_buffer* buffer_;
 
index d810625..c3ae6c4 100644 (file)
@@ -188,11 +188,6 @@ class WriteOptions {
   /// \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; }
 
@@ -468,7 +463,6 @@ class CallOpRecvMessage {
         *status = false;
       }
     }
-    message_ = nullptr;
   }
 
   void SetInterceptionHookPoint(
@@ -565,7 +559,6 @@ class CallOpGenericRecvMessage {
         *status = false;
       }
     }
-    deserialize_.reset();
   }
 
   void SetInterceptionHookPoint(
@@ -580,6 +573,7 @@ class CallOpGenericRecvMessage {
     interceptor_methods->AddInterceptionHookPoint(
         experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
     if (!got_message) interceptor_methods->SetRecvMessage(nullptr, nullptr);
+    deserialize_.reset();
   }
   void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
     hijacked_ = true;
index 9df233b..836c287 100644 (file)
 #include <grpcpp/impl/codegen/time.h>
 
 namespace grpc_impl {
+class ClientContext;
 class CompletionQueue;
-}
+}  // namespace grpc_impl
 
 namespace grpc {
 class ChannelInterface;
-class ClientContext;
 
 template <class R>
 class ClientReader;
@@ -129,7 +129,7 @@ class ChannelInterface {
   friend class ::grpc::internal::RpcMethod;
   friend class ::grpc::internal::InterceptedChannel;
   virtual internal::Call CreateCall(const internal::RpcMethod& method,
-                                    ClientContext* context,
+                                    ::grpc_impl::ClientContext* context,
                                     ::grpc_impl::CompletionQueue* cq) = 0;
   virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
                                 internal::Call* call) = 0;
@@ -149,7 +149,7 @@ class ChannelInterface {
   // 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,
+                                            ::grpc_impl::ClientContext* context,
                                             ::grpc_impl::CompletionQueue* cq,
                                             size_t interceptor_pos) {
     return internal::Call();
index dda9aec..6cba583 100644 (file)
 
 namespace grpc_impl {
 class Channel;
-}
+class ClientContext;
+}  // namespace grpc_impl
 
 namespace grpc {
 
-class ClientContext;
-
 namespace internal {
 class RpcMethod;
 
index 999d8fc..0238946 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2019 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
-/// A ClientContext allows the person implementing a service client to:
-///
-/// - Add custom metadata key-value pairs that will propagated to the server
-/// side.
-/// - Control call settings such as compression and authentication.
-/// - Initial and trailing metadata coming from the server.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call they are invoked with, that
-/// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistent at channel construction time
-/// (see \a grpc::CreateCustomChannel).
-///
-/// \warning ClientContext instances should \em not be reused across rpcs.
-
 #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
 #define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
 
-#include <map>
-#include <memory>
-#include <mutex>
-#include <string>
-
-#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>
-#include <grpcpp/impl/codegen/string_ref.h>
-#include <grpcpp/impl/codegen/sync.h>
-#include <grpcpp/impl/codegen/time.h>
-
-struct census_context;
-struct grpc_call;
-
-namespace grpc_impl {
+#include <grpcpp/impl/codegen/client_context_impl.h>
 
-class CallCredentials;
-class Channel;
-class CompletionQueue;
-}  // namespace grpc_impl
 namespace grpc {
 
-class ChannelInterface;
-class ClientContext;
-
-namespace internal {
-class RpcMethod;
-class CallOpClientRecvStatus;
-class CallOpRecvInitialMetadata;
-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;
-class ClientCallbackUnaryImpl;
-}  // namespace internal
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ClientAsyncReader;
-template <class W>
-class ClientAsyncWriter;
-template <class W, class R>
-class ClientAsyncReaderWriter;
-template <class R>
-class ClientAsyncResponseReader;
-class ServerContext;
-
-/// Options for \a ClientContext::FromServerContext specifying which traits from
-/// the \a ServerContext to propagate (copy) from it into a new \a
-/// ClientContext.
-///
-/// \see ClientContext::FromServerContext
-class PropagationOptions {
- public:
-  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
-
-  PropagationOptions& enable_deadline_propagation() {
-    propagate_ |= GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& disable_deadline_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_stats_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_stats_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_tracing_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_tracing_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_cancellation_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  PropagationOptions& disable_cancellation_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  uint32_t c_bitmask() const { return propagate_; }
-
- private:
-  uint32_t propagate_;
-};
-
-namespace testing {
-class InteropClientContextInspector;
-}  // namespace testing
-
-/// A ClientContext allows the person implementing a service client to:
-///
-/// - Add custom metadata key-value pairs that will propagated to the server
-///   side.
-/// - Control call settings such as compression and authentication.
-/// - Initial and trailing metadata coming from the server.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call they are invoked with, that
-/// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistent at channel construction time
-/// (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();
-  ~ClientContext();
-
-  /// Create a new \a ClientContext as a child of an incoming server call,
-  /// according to \a options (\see PropagationOptions).
-  ///
-  /// \param server_context The source server context to use as the basis for
-  /// constructing the client context.
-  /// \param options The options controlling what to copy from the \a
-  /// server_context.
-  ///
-  /// \return A newly constructed \a ClientContext instance based on \a
-  /// server_context, with traits propagated (copied) according to \a options.
-  static std::unique_ptr<ClientContext> FromServerContext(
-      const ServerContext& server_context,
-      PropagationOptions options = PropagationOptions());
-
-  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
-  /// a client call. These are made available at the server side by the \a
-  /// grpc::ServerContext::client_metadata() method.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
-  /// end in "-bin".
-  /// \param meta_value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  ///
-  /// Metadata must conform to the following format:
-  /// Custom-Metadata -> Binary-Header / ASCII-Header
-  /// Binary-Header -> {Header-Name "-bin" } {binary value}
-  /// ASCII-Header -> Header-Name ASCII-Value
-  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
-  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
-  void AddMetadata(const grpc::string& meta_key,
-                   const grpc::string& meta_value);
-
-  /// Return a collection of initial metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method should only be called after initial metadata has been
-  /// received. For streaming calls, see \a
-  /// ClientReaderInterface::WaitForInitialMetadata().
-  ///
-  /// \return A multimap of initial metadata key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerInitialMetadata() const {
-    GPR_CODEGEN_ASSERT(initial_metadata_received_);
-    return *recv_initial_metadata_.map();
-  }
-
-  /// Return a collection of trailing metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method is only callable once the stream has finished.
-  ///
-  /// \return A multimap of metadata trailing key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerTrailingMetadata() const {
-    // TODO(yangg) check finished
-    return *trailing_metadata_.map();
-  }
-
-  /// Set the deadline for the client call.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param deadline the deadline for the client call. Units are determined by
-  /// the type used. The deadline is an absolute (not relative) time.
-  template <typename T>
-  void set_deadline(const T& deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    deadline_ = deadline_tp.raw_time();
-  }
-
-  /// EXPERIMENTAL: Indicate that this request is idempotent.
-  /// By default, RPCs are assumed to <i>not</i> be idempotent.
-  ///
-  /// If true, the gRPC library assumes that it's safe to initiate
-  /// this RPC multiple times.
-  void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
-
-  /// EXPERIMENTAL: Set this request to be cacheable.
-  /// If set, grpc is free to use the HTTP GET verb for sending the request,
-  /// with the possibility of receiving a cached response.
-  void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
-
-  /// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
-  /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
-  /// If set, if an RPC is made when a channel's connectivity state is
-  /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
-  /// and the channel will wait until the channel is READY before making the
-  /// call.
-  void set_wait_for_ready(bool wait_for_ready) {
-    wait_for_ready_ = wait_for_ready;
-    wait_for_ready_explicitly_set_ = true;
-  }
-
-  /// DEPRECATED: Use set_wait_for_ready() instead.
-  void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
-
-  /// Return the deadline for the client call.
-  std::chrono::system_clock::time_point deadline() const {
-    return Timespec2Timepoint(deadline_);
-  }
-
-  /// Return a \a gpr_timespec representation of the client call's deadline.
-  gpr_timespec raw_deadline() const { return deadline_; }
-
-  /// Set the per call authority header (see
-  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
-  void set_authority(const grpc::string& authority) { authority_ = authority; }
-
-  /// Return the authentication context for this client call.
-  ///
-  /// \see grpc::AuthContext.
-  std::shared_ptr<const AuthContext> auth_context() const {
-    if (auth_context_.get() == nullptr) {
-      auth_context_ = CreateAuthContext(call_);
-    }
-    return auth_context_;
-  }
-
-  /// Set credentials for the client call.
-  ///
-  /// A credentials object encapsulates all the state needed by a client to
-  /// authenticate with a server and make various assertions, e.g., about the
-  /// client’s identity, role, or whether it is authorized to make a particular
-  /// call.
-  ///
-  /// \see  https://grpc.io/docs/guides/auth.html
-  void set_credentials(
-      const std::shared_ptr<grpc_impl::CallCredentials>& creds) {
-    creds_ = creds;
-  }
-
-  /// Return the compression algorithm the client call will request be used.
-  /// Note that the gRPC runtime may decide to ignore this request, for example,
-  /// due to resource constraints.
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-
-  /// Set \a algorithm to be the compression algorithm used for the client call.
-  ///
-  /// \param algorithm The compression algorithm used for the client call.
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  /// Flag whether the initial metadata should be \a corked
-  ///
-  /// If \a corked is true, then the initial metadata will be coalesced with the
-  /// write of first message in the stream. As a result, any tag set for the
-  /// initial metadata operation (starting a client-streaming or bidi-streaming
-  /// RPC) will not actually be sent to the completion queue or delivered
-  /// via Next.
-  ///
-  /// \param corked The flag indicating whether the initial metadata is to be
-  /// corked or not.
-  void set_initial_metadata_corked(bool corked) {
-    initial_metadata_corked_ = corked;
-  }
-
-  /// Return the peer uri in a string.
-  ///
-  /// \warning This value is never authenticated or subject to any security
-  /// related code. It must not be used for any authentication related
-  /// functionality. Instead, use auth_context.
-  ///
-  /// \return The call's peer URI.
-  grpc::string peer() const;
-
-  /// Get and set census context.
-  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
-  struct census_context* census_context() const {
-    return census_context_;
-  }
-
-  /// Send a best-effort out-of-band cancel on the call associated with
-  /// this client context.  The call could be in any stage; e.g., if it is
-  /// already finished, it may still return success.
-  ///
-  /// There is no guarantee the call will be cancelled.
-  ///
-  /// Note that TryCancel() does not change any of the tags that are pending
-  /// on the completion queue. All pending tags will still be delivered
-  /// (though their ok result may reflect the effect of cancellation).
-  void TryCancel();
-
-  /// Global Callbacks
-  ///
-  /// Can be set exactly once per application to install hooks whenever
-  /// a client context is constructed and destructed.
-  class GlobalCallbacks {
-   public:
-    virtual ~GlobalCallbacks() {}
-    virtual void DefaultConstructor(ClientContext* context) = 0;
-    virtual void Destructor(ClientContext* context) = 0;
-  };
-  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
-
-  /// Should be used for framework-level extensions only.
-  /// Applications never need to call this method.
-  grpc_call* c_call() { return call_; }
-
-  /// EXPERIMENTAL debugging API
-  ///
-  /// if status is not ok() for an RPC, this will return a detailed string
-  /// of the gRPC Core error that led to the failure. It should not be relied
-  /// upon for anything other than gaining more debug data in failure cases.
-  grpc::string debug_error_string() const { return debug_error_string_; }
-
- private:
-  // Disallow copy and assign.
-  ClientContext(const ClientContext&);
-  ClientContext& operator=(const ClientContext&);
-
-  friend class ::grpc::testing::InteropClientContextInspector;
-  friend class ::grpc::internal::CallOpClientRecvStatus;
-  friend class ::grpc::internal::CallOpRecvInitialMetadata;
-  friend class ::grpc_impl::Channel;
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncReader;
-  template <class W>
-  friend class ::grpc::ClientAsyncWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncResponseReader;
-  template <class InputMessage, class OutputMessage>
-  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;
-  friend class ::grpc::internal::ClientCallbackUnaryImpl;
-
-  // Used by friend class CallOpClientRecvStatus
-  void set_debug_error_string(const grpc::string& debug_error_string) {
-    debug_error_string_ = debug_error_string;
-  }
-
-  grpc_call* call() const { return call_; }
-  void set_call(grpc_call* call,
-                const std::shared_ptr<::grpc_impl::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) |
-           (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
-           (wait_for_ready_explicitly_set_
-                ? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
-                : 0) |
-           (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
-  }
-
-  grpc::string authority() { return authority_; }
-
-  void SendCancelToInterceptors();
-
-  bool initial_metadata_received_;
-  bool wait_for_ready_;
-  bool wait_for_ready_explicitly_set_;
-  bool idempotent_;
-  bool cacheable_;
-  std::shared_ptr<::grpc_impl::Channel> channel_;
-  grpc::internal::Mutex mu_;
-  grpc_call* call_;
-  bool call_canceled_;
-  gpr_timespec deadline_;
-  grpc::string authority_;
-  std::shared_ptr<grpc_impl::CallCredentials> creds_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  struct census_context* census_context_;
-  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
-  mutable internal::MetadataMap recv_initial_metadata_;
-  mutable internal::MetadataMap trailing_metadata_;
-
-  grpc_call* propagate_from_call_;
-  PropagationOptions propagation_options_;
-
-  grpc_compression_algorithm compression_algorithm_;
-  bool initial_metadata_corked_;
-
-  grpc::string debug_error_string_;
-
-  experimental::ClientRpcInfo rpc_info_;
-};
+typedef ::grpc_impl::ClientContext ClientContext;
+typedef ::grpc_impl::PropagationOptions PropagationOptions;
 
 }  // namespace grpc
 
diff --git a/include/grpcpp/impl/codegen/client_context_impl.h b/include/grpcpp/impl/codegen/client_context_impl.h
new file mode 100644 (file)
index 0000000..8491215
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/// A ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+/// side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistent at channel construction time
+/// (see \a grpc::CreateCustomChannel).
+///
+/// \warning ClientContext instances should \em not be reused across rpcs.
+
+#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#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>
+#include <grpcpp/impl/codegen/string_ref.h>
+#include <grpcpp/impl/codegen/sync.h>
+#include <grpcpp/impl/codegen/time.h>
+
+struct census_context;
+struct grpc_call;
+
+namespace grpc {
+
+class ChannelInterface;
+
+namespace internal {
+class RpcMethod;
+class CallOpClientRecvStatus;
+class CallOpRecvInitialMetadata;
+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;
+class ClientCallbackUnaryImpl;
+}  // namespace internal
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ClientAsyncReader;
+template <class W>
+class ClientAsyncWriter;
+template <class W, class R>
+class ClientAsyncReaderWriter;
+template <class R>
+class ClientAsyncResponseReader;
+
+namespace testing {
+class InteropClientContextInspector;
+}  // namespace testing
+}  // namespace grpc
+namespace grpc_impl {
+
+class CallCredentials;
+class Channel;
+class CompletionQueue;
+class ServerContext;
+
+/// Options for \a ClientContext::FromServerContext specifying which traits from
+/// the \a ServerContext to propagate (copy) from it into a new \a
+/// ClientContext.
+///
+/// \see ClientContext::FromServerContext
+class PropagationOptions {
+ public:
+  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
+
+  PropagationOptions& enable_deadline_propagation() {
+    propagate_ |= GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& disable_deadline_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_stats_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_stats_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_tracing_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_tracing_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_cancellation_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  PropagationOptions& disable_cancellation_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  uint32_t c_bitmask() const { return propagate_; }
+
+ private:
+  uint32_t propagate_;
+};
+
+/// A ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+///   side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistent at channel construction time
+/// (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();
+  ~ClientContext();
+
+  /// Create a new \a ClientContext as a child of an incoming server call,
+  /// according to \a options (\see PropagationOptions).
+  ///
+  /// \param server_context The source server context to use as the basis for
+  /// constructing the client context.
+  /// \param options The options controlling what to copy from the \a
+  /// server_context.
+  ///
+  /// \return A newly constructed \a ClientContext instance based on \a
+  /// server_context, with traits propagated (copied) according to \a options.
+  static std::unique_ptr<ClientContext> FromServerContext(
+      const grpc_impl::ServerContext& server_context,
+      PropagationOptions options = PropagationOptions());
+
+  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
+  /// a client call. These are made available at the server side by the \a
+  /// grpc::ServerContext::client_metadata() method.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+  /// end in "-bin".
+  /// \param meta_value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  ///
+  /// Metadata must conform to the following format:
+  /// Custom-Metadata -> Binary-Header / ASCII-Header
+  /// Binary-Header -> {Header-Name "-bin" } {binary value}
+  /// ASCII-Header -> Header-Name ASCII-Value
+  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
+  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
+  void AddMetadata(const grpc::string& meta_key,
+                   const grpc::string& meta_value);
+
+  /// Return a collection of initial metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method should only be called after initial metadata has been
+  /// received. For streaming calls, see \a
+  /// ClientReaderInterface::WaitForInitialMetadata().
+  ///
+  /// \return A multimap of initial metadata key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerInitialMetadata() const {
+    GPR_CODEGEN_ASSERT(initial_metadata_received_);
+    return *recv_initial_metadata_.map();
+  }
+
+  /// Return a collection of trailing metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method is only callable once the stream has finished.
+  ///
+  /// \return A multimap of metadata trailing key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerTrailingMetadata() const {
+    // TODO(yangg) check finished
+    return *trailing_metadata_.map();
+  }
+
+  /// Set the deadline for the client call.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param deadline the deadline for the client call. Units are determined by
+  /// the type used. The deadline is an absolute (not relative) time.
+  template <typename T>
+  void set_deadline(const T& deadline) {
+    grpc::TimePoint<T> deadline_tp(deadline);
+    deadline_ = deadline_tp.raw_time();
+  }
+
+  /// EXPERIMENTAL: Indicate that this request is idempotent.
+  /// By default, RPCs are assumed to <i>not</i> be idempotent.
+  ///
+  /// If true, the gRPC library assumes that it's safe to initiate
+  /// this RPC multiple times.
+  void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
+
+  /// EXPERIMENTAL: Set this request to be cacheable.
+  /// If set, grpc is free to use the HTTP GET verb for sending the request,
+  /// with the possibility of receiving a cached response.
+  void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
+
+  /// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
+  /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
+  /// If set, if an RPC is made when a channel's connectivity state is
+  /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
+  /// and the channel will wait until the channel is READY before making the
+  /// call.
+  void set_wait_for_ready(bool wait_for_ready) {
+    wait_for_ready_ = wait_for_ready;
+    wait_for_ready_explicitly_set_ = true;
+  }
+
+  /// DEPRECATED: Use set_wait_for_ready() instead.
+  void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
+
+  /// Return the deadline for the client call.
+  std::chrono::system_clock::time_point deadline() const {
+    return grpc::Timespec2Timepoint(deadline_);
+  }
+
+  /// Return a \a gpr_timespec representation of the client call's deadline.
+  gpr_timespec raw_deadline() const { return deadline_; }
+
+  /// Set the per call authority header (see
+  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
+  void set_authority(const grpc::string& authority) { authority_ = authority; }
+
+  /// Return the authentication context for this client call.
+  ///
+  /// \see grpc::AuthContext.
+  std::shared_ptr<const grpc::AuthContext> auth_context() const {
+    if (auth_context_.get() == nullptr) {
+      auth_context_ = grpc::CreateAuthContext(call_);
+    }
+    return auth_context_;
+  }
+
+  /// Set credentials for the client call.
+  ///
+  /// A credentials object encapsulates all the state needed by a client to
+  /// authenticate with a server and make various assertions, e.g., about the
+  /// client’s identity, role, or whether it is authorized to make a particular
+  /// call.
+  ///
+  /// \see  https://grpc.io/docs/guides/auth.html
+  void set_credentials(
+      const std::shared_ptr<grpc_impl::CallCredentials>& creds) {
+    creds_ = creds;
+  }
+
+  /// Return the compression algorithm the client call will request be used.
+  /// Note that the gRPC runtime may decide to ignore this request, for example,
+  /// due to resource constraints.
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+
+  /// Set \a algorithm to be the compression algorithm used for the client call.
+  ///
+  /// \param algorithm The compression algorithm used for the client call.
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  /// Flag whether the initial metadata should be \a corked
+  ///
+  /// If \a corked is true, then the initial metadata will be coalesced with the
+  /// write of first message in the stream. As a result, any tag set for the
+  /// initial metadata operation (starting a client-streaming or bidi-streaming
+  /// RPC) will not actually be sent to the completion queue or delivered
+  /// via Next.
+  ///
+  /// \param corked The flag indicating whether the initial metadata is to be
+  /// corked or not.
+  void set_initial_metadata_corked(bool corked) {
+    initial_metadata_corked_ = corked;
+  }
+
+  /// Return the peer uri in a string.
+  ///
+  /// \warning This value is never authenticated or subject to any security
+  /// related code. It must not be used for any authentication related
+  /// functionality. Instead, use auth_context.
+  ///
+  /// \return The call's peer URI.
+  grpc::string peer() const;
+
+  /// Get and set census context.
+  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
+  struct census_context* census_context() const {
+    return census_context_;
+  }
+
+  /// Send a best-effort out-of-band cancel on the call associated with
+  /// this client context.  The call could be in any stage; e.g., if it is
+  /// already finished, it may still return success.
+  ///
+  /// There is no guarantee the call will be cancelled.
+  ///
+  /// Note that TryCancel() does not change any of the tags that are pending
+  /// on the completion queue. All pending tags will still be delivered
+  /// (though their ok result may reflect the effect of cancellation).
+  void TryCancel();
+
+  /// Global Callbacks
+  ///
+  /// Can be set exactly once per application to install hooks whenever
+  /// a client context is constructed and destructed.
+  class GlobalCallbacks {
+   public:
+    virtual ~GlobalCallbacks() {}
+    virtual void DefaultConstructor(ClientContext* context) = 0;
+    virtual void Destructor(ClientContext* context) = 0;
+  };
+  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
+
+  /// Should be used for framework-level extensions only.
+  /// Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
+  /// EXPERIMENTAL debugging API
+  ///
+  /// if status is not ok() for an RPC, this will return a detailed string
+  /// of the gRPC Core error that led to the failure. It should not be relied
+  /// upon for anything other than gaining more debug data in failure cases.
+  grpc::string debug_error_string() const { return debug_error_string_; }
+
+ private:
+  // Disallow copy and assign.
+  ClientContext(const ClientContext&);
+  ClientContext& operator=(const ClientContext&);
+
+  friend class ::grpc::testing::InteropClientContextInspector;
+  friend class ::grpc::internal::CallOpClientRecvStatus;
+  friend class ::grpc::internal::CallOpRecvInitialMetadata;
+  friend class ::grpc_impl::Channel;
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncReader;
+  template <class W>
+  friend class ::grpc::ClientAsyncWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncResponseReader;
+  template <class InputMessage, class OutputMessage>
+  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;
+  friend class ::grpc::internal::ClientCallbackUnaryImpl;
+
+  // Used by friend class CallOpClientRecvStatus
+  void set_debug_error_string(const grpc::string& debug_error_string) {
+    debug_error_string_ = debug_error_string;
+  }
+
+  grpc_call* call() const { return call_; }
+  void set_call(grpc_call* call,
+                const std::shared_ptr<::grpc_impl::Channel>& channel);
+
+  grpc::experimental::ClientRpcInfo* set_client_rpc_info(
+      const char* method, grpc::internal::RpcMethod::RpcType type,
+      grpc::ChannelInterface* channel,
+      const std::vector<std::unique_ptr<
+          grpc::experimental::ClientInterceptorFactoryInterface>>& creators,
+      size_t interceptor_pos) {
+    rpc_info_ = grpc::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) |
+           (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
+           (wait_for_ready_explicitly_set_
+                ? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+                : 0) |
+           (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
+  }
+
+  grpc::string authority() { return authority_; }
+
+  void SendCancelToInterceptors();
+
+  bool initial_metadata_received_;
+  bool wait_for_ready_;
+  bool wait_for_ready_explicitly_set_;
+  bool idempotent_;
+  bool cacheable_;
+  std::shared_ptr<::grpc_impl::Channel> channel_;
+  grpc::internal::Mutex mu_;
+  grpc_call* call_;
+  bool call_canceled_;
+  gpr_timespec deadline_;
+  grpc::string authority_;
+  std::shared_ptr<grpc_impl::CallCredentials> creds_;
+  mutable std::shared_ptr<const grpc::AuthContext> auth_context_;
+  struct census_context* census_context_;
+  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
+  mutable grpc::internal::MetadataMap recv_initial_metadata_;
+  mutable grpc::internal::MetadataMap trailing_metadata_;
+
+  grpc_call* propagate_from_call_;
+  PropagationOptions propagation_options_;
+
+  grpc_compression_algorithm compression_algorithm_;
+  bool initial_metadata_corked_;
+
+  grpc::string debug_error_string_;
+
+  grpc::experimental::ClientRpcInfo rpc_info_;
+};
+
+}  // namespace grpc_impl
+
+#endif  // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
index a4c85a7..9e978b6 100644 (file)
 namespace grpc_impl {
 
 class Channel;
-}
+class ClientContext;
+}  // namespace grpc_impl
 
 namespace grpc {
 
-class ClientContext;
-
 namespace internal {
 class InterceptorBatchMethodsImpl;
 }
@@ -96,7 +95,7 @@ class ClientRpcInfo {
 
   /// Return a pointer to the underlying ClientContext structure associated
   /// with the RPC to support features that apply to it
-  grpc::ClientContext* client_context() { return ctx_; }
+  grpc_impl::ClientContext* client_context() { return ctx_; }
 
   /// Return the type of the RPC (unary or a streaming flavor)
   Type type() const { return type_; }
@@ -119,8 +118,9 @@ class ClientRpcInfo {
   ClientRpcInfo() = default;
 
   // Constructor will only be called from ClientContext
-  ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
-                const char* method, grpc::ChannelInterface* channel)
+  ClientRpcInfo(grpc_impl::ClientContext* ctx,
+                internal::RpcMethod::RpcType type, const char* method,
+                grpc::ChannelInterface* channel)
       : ctx_(ctx),
         type_(static_cast<Type>(type)),
         method_(method),
@@ -160,7 +160,7 @@ class ClientRpcInfo {
     }
   }
 
-  grpc::ClientContext* ctx_ = nullptr;
+  grpc_impl::ClientContext* ctx_ = nullptr;
   // TODO(yashykt): make type_ const once move-assignment is deleted
   Type type_{Type::UNKNOWN};
   const char* method_ = nullptr;
@@ -170,7 +170,7 @@ class ClientRpcInfo {
   size_t hijacked_interceptor_ = 0;
 
   friend class internal::InterceptorBatchMethodsImpl;
-  friend class grpc::ClientContext;
+  friend class grpc_impl::ClientContext;
 };
 
 // PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL
index e0f692b..599dd1e 100644 (file)
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/status.h>
 
-namespace grpc {
+namespace grpc_impl {
 
 class ClientContext;
+}  // namespace grpc_impl
+namespace grpc {
 
 namespace internal {
 class RpcMethod;
 /// Wrapper that performs a blocking unary call
 template <class InputMessage, class OutputMessage>
 Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
-                         ClientContext* context, const InputMessage& request,
-                         OutputMessage* result) {
+                         grpc_impl::ClientContext* context,
+                         const InputMessage& request, OutputMessage* result) {
   return BlockingUnaryCallImpl<InputMessage, OutputMessage>(
              channel, method, context, request, result)
       .status();
@@ -45,8 +47,8 @@ template <class InputMessage, class OutputMessage>
 class BlockingUnaryCallImpl {
  public:
   BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
-                        ClientContext* context, const InputMessage& request,
-                        OutputMessage* result) {
+                        grpc_impl::ClientContext* context,
+                        const InputMessage& request, OutputMessage* result) {
     CompletionQueue cq(grpc_completion_queue_attributes{
         GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
         nullptr});  // Pluckable completion queue
index 5435f2f..0a6b0b0 100644 (file)
@@ -46,6 +46,7 @@ namespace grpc_impl {
 class Channel;
 class Server;
 class ServerBuilder;
+class ServerContext;
 }  // namespace grpc_impl
 namespace grpc {
 
@@ -65,8 +66,6 @@ class ServerReaderWriterBody;
 }  // namespace internal
 
 class ChannelInterface;
-class ClientContext;
-class ServerContext;
 class ServerInterface;
 
 namespace internal {
@@ -186,8 +185,8 @@ class CompletionQueue : private ::grpc::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 success, updated to point to the event's tag.
+  /// \param ok [out] Upon success, 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.
   ///
@@ -206,8 +205,8 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
   /// 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
+  /// \param tag [out] Upon success, updated to point to the event's tag.
+  /// \param ok [out] Upon success, true if read a regular event, false
   /// otherwise.
   /// \param deadline [in] How long to block in wait for an event.
   ///
@@ -278,7 +277,7 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
   template <::grpc::StatusCode code>
   friend class ::grpc::internal::ErrorMethodHandler;
   friend class ::grpc_impl::Server;
-  friend class ::grpc::ServerContext;
+  friend class ::grpc_impl::ServerContext;
   friend class ::grpc::ServerInterface;
   template <class InputMessage, class OutputMessage>
   friend class ::grpc::internal::BlockingUnaryCallImpl;
index 8c2e9e6..3c9ab34 100644 (file)
 #ifdef GRPC_USE_PROTO_LITE
 #include <google/protobuf/message_lite.h>
 #define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite
+#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite
 #else
 #include <google/protobuf/message.h>
 #define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
+#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite
 #endif
 #endif
 
@@ -76,6 +78,7 @@ namespace grpc {
 namespace protobuf {
 
 typedef GRPC_CUSTOM_MESSAGE Message;
+typedef GRPC_CUSTOM_MESSAGELITE MessageLite;
 typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
 
 typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
index 3792c3d..02b5033 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
 #define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
 
+#include <grpc/impl/codegen/byte_buffer.h>
 #include <grpc/impl/codegen/byte_buffer_reader.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/impl/codegen/sync.h>
index b0f57f7..18c7cf3 100644 (file)
@@ -174,20 +174,22 @@ class InterceptorBatchMethods {
   /// Returns a pointer to the modifiable received message. Note that the
   /// message is already deserialized but the type is not set; the interceptor
   /// should static_cast to the appropriate type before using it. This is valid
-  /// for POST_RECV_MESSAGE interceptions; nullptr for not valid
+  /// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not
+  /// valid
   virtual void* GetRecvMessage() = 0;
 
   /// Returns a modifiable multimap of the received initial metadata.
-  /// Valid for POST_RECV_INITIAL_METADATA interceptions; nullptr if not valid
+  /// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA
+  /// interceptions; nullptr if not valid
   virtual std::multimap<grpc::string_ref, grpc::string_ref>*
   GetRecvInitialMetadata() = 0;
 
-  /// Returns a modifiable view of the received status on POST_RECV_STATUS
-  /// interceptions; nullptr if not valid.
+  /// Returns a modifiable view of the received status on PRE_RECV_STATUS and
+  /// POST_RECV_STATUS interceptions; nullptr if not valid.
   virtual Status* GetRecvStatus() = 0;
 
   /// Returns a modifiable multimap of the received trailing metadata on
-  /// POST_RECV_STATUS interceptions; nullptr if not valid
+  /// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid
   virtual std::multimap<grpc::string_ref, grpc::string_ref>*
   GetRecvTrailingMetadata() = 0;
 
index 107bec6..83544c6 100644 (file)
 namespace grpc {
 namespace experimental {
 
-// This is per rpc struct for the allocator. We can potentially put the grpc
-// call arena in here in the future.
+// NOTE: This is an API for advanced users who need custom allocators.
+// Per rpc struct for the allocator. This is the interface to return to user.
+class RpcAllocatorState {
+ public:
+  virtual ~RpcAllocatorState() = default;
+  // Optionally deallocate request early to reduce the size of working set.
+  // A custom MessageAllocator needs to be registered to make use of this.
+  // This is not abstract because implementing it is optional.
+  virtual void FreeRequest() {}
+};
+
+// This is the interface returned by the allocator.
+// grpc library will call the methods to get request/response pointers and to
+// release the object when it is done.
 template <typename RequestT, typename ResponseT>
-struct RpcAllocatorInfo {
-  RequestT* request;
-  ResponseT* response;
-  // per rpc allocator internal state. MessageAllocator can set it when
-  // AllocateMessages is called and use it later.
-  void* allocator_state;
+class MessageHolder : public RpcAllocatorState {
+ public:
+  // Release this object. For example, if the custom allocator's
+  // AllocateMessasge creates an instance of a subclass with new, the Release()
+  // should do a "delete this;".
+  virtual void Release() = 0;
+  RequestT* request() { return request_; }
+  ResponseT* response() { return response_; }
+
+ protected:
+  void set_request(RequestT* request) { request_ = request; }
+  void set_response(ResponseT* response) { response_ = response; }
+
+ private:
+  // NOTE: subclasses should set these pointers.
+  RequestT* request_;
+  ResponseT* response_;
 };
 
-// Implementations need to be thread-safe
+// A custom allocator can be set via the generated code to a callback unary
+// method, such as SetMessageAllocatorFor_Echo(custom_allocator). The allocator
+// needs to be alive for the lifetime of the server.
+// Implementations need to be thread-safe.
 template <typename RequestT, typename ResponseT>
 class MessageAllocator {
  public:
   virtual ~MessageAllocator() = default;
-  // Allocate both request and response
-  virtual void AllocateMessages(
-      RpcAllocatorInfo<RequestT, ResponseT>* info) = 0;
-  // Optional: deallocate request early, called by
-  // ServerCallbackRpcController::ReleaseRequest
-  virtual void DeallocateRequest(RpcAllocatorInfo<RequestT, ResponseT>* info) {}
-  // Deallocate response and request (if applicable)
-  virtual void DeallocateMessages(
-      RpcAllocatorInfo<RequestT, ResponseT>* info) = 0;
+  virtual MessageHolder<RequestT, ResponseT>* AllocateMessages() = 0;
 };
 
 }  // namespace experimental
index d9db6de..f9a7d3c 100644 (file)
@@ -42,7 +42,7 @@ extern CoreCodegenInterface* g_core_codegen_interface;
 
 // ProtoBufferWriter must be a subclass of ::protobuf::io::ZeroCopyOutputStream.
 template <class ProtoBufferWriter, class T>
-Status GenericSerialize(const grpc::protobuf::Message& msg, ByteBuffer* bb,
+Status GenericSerialize(const grpc::protobuf::MessageLite& msg, ByteBuffer* bb,
                         bool* own_buffer) {
   static_assert(std::is_base_of<protobuf::io::ZeroCopyOutputStream,
                                 ProtoBufferWriter>::value,
@@ -68,7 +68,8 @@ Status GenericSerialize(const grpc::protobuf::Message& msg, ByteBuffer* bb,
 
 // BufferReader must be a subclass of ::protobuf::io::ZeroCopyInputStream.
 template <class ProtoBufferReader, class T>
-Status GenericDeserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) {
+Status GenericDeserialize(ByteBuffer* buffer,
+                          grpc::protobuf::MessageLite* msg) {
   static_assert(std::is_base_of<protobuf::io::ZeroCopyInputStream,
                                 ProtoBufferReader>::value,
                 "ProtoBufferReader must be a subclass of "
@@ -102,15 +103,17 @@ Status GenericDeserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) {
 // objects and grpc_byte_buffers. More information about SerializationTraits can
 // be found in include/grpcpp/impl/codegen/serialization_traits.h.
 template <class T>
-class SerializationTraits<T, typename std::enable_if<std::is_base_of<
-                                 grpc::protobuf::Message, T>::value>::type> {
+class SerializationTraits<
+    T, typename std::enable_if<
+           std::is_base_of<grpc::protobuf::MessageLite, T>::value>::type> {
  public:
-  static Status Serialize(const grpc::protobuf::Message& msg, ByteBuffer* bb,
-                          bool* own_buffer) {
+  static Status Serialize(const grpc::protobuf::MessageLite& msg,
+                          ByteBuffer* bb, bool* own_buffer) {
     return GenericSerialize<ProtoBufferWriter, T>(msg, bb, own_buffer);
   }
 
-  static Status Deserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) {
+  static Status Deserialize(ByteBuffer* buffer,
+                            grpc::protobuf::MessageLite* msg) {
     return GenericDeserialize<ProtoBufferReader, T>(buffer, msg);
   }
 };
index 21fb2ac..0b16fee 100644 (file)
 #include <grpcpp/impl/codegen/rpc_method.h>
 #include <grpcpp/impl/codegen/status.h>
 
-namespace grpc {
+namespace grpc_impl {
 class ServerContext;
+}
 
+namespace grpc {
 namespace internal {
 /// Base class for running an RPC handler.
 class MethodHandler {
@@ -50,7 +52,7 @@ class MethodHandler {
     /// \param 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,
+    HandlerParameter(Call* c, ::grpc_impl::ServerContext* context, void* req,
                      Status req_status, void* handler_data,
                      std::function<void()> requester)
         : call(c),
@@ -61,7 +63,7 @@ class MethodHandler {
           call_requester(std::move(requester)) {}
     ~HandlerParameter() {}
     Call* call;
-    ServerContext* server_context;
+    ::grpc_impl::ServerContext* server_context;
     void* request;
     Status status;
     void* internal_data;
index 3f6d5cd..ab47873 100644 (file)
@@ -29,7 +29,7 @@
 #include <grpcpp/impl/codegen/config.h>
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/message_allocator.h>
-#include <grpcpp/impl/codegen/server_context.h>
+#include <grpcpp/impl/codegen/server_context_impl.h>
 #include <grpcpp/impl/codegen/server_interface.h>
 #include <grpcpp/impl/codegen/status.h>
 
@@ -53,7 +53,7 @@ class ServerReactor {
   virtual void OnCancel() = 0;
 
  private:
-  friend class ::grpc::ServerContext;
+  friend class ::grpc_impl::ServerContext;
   template <class Request, class Response>
   friend class CallbackClientStreamingHandler;
   template <class Request, class Response>
@@ -77,6 +77,24 @@ class ServerReactor {
   std::atomic_int on_cancel_conditions_remaining_{2};
 };
 
+template <class Request, class Response>
+class DefaultMessageHolder
+    : public experimental::MessageHolder<Request, Response> {
+ public:
+  DefaultMessageHolder() {
+    this->set_request(&request_obj_);
+    this->set_response(&response_obj_);
+  }
+  void Release() override {
+    // the object is allocated in the call arena.
+    this->~DefaultMessageHolder<Request, Response>();
+  }
+
+ private:
+  Request request_obj_;
+  Response response_obj_;
+};
+
 }  // namespace internal
 
 namespace experimental {
@@ -138,12 +156,8 @@ class ServerCallbackRpcController {
   virtual void ClearCancelCallback() = 0;
 
   // NOTE: This is an API for advanced users who need custom allocators.
-  // Optionally deallocate request early to reduce the size of working set.
-  // A custom MessageAllocator needs to be registered to make use of this.
-  virtual void FreeRequest() = 0;
-  // NOTE: This is an API for advanced users who need custom allocators.
   // Get and maybe mutate the allocator state associated with the current RPC.
-  virtual void* GetAllocatorState() = 0;
+  virtual RpcAllocatorState* GetRpcAllocatorState() = 0;
 };
 
 // NOTE: The actual streaming object classes are provided
@@ -299,7 +313,7 @@ class ServerBidiReactor : public internal::ServerReactor {
   /// is a result of the client calling StartCall().
   ///
   /// \param[in] context The context object now associated with this RPC
-  virtual void OnStarted(ServerContext* context) {}
+  virtual void OnStarted(::grpc_impl::ServerContext* context) {}
 
   /// Notifies the application that an explicit StartSendInitialMetadata
   /// operation completed. Not used when the sending of initial metadata
@@ -334,7 +348,8 @@ class ServerBidiReactor : public internal::ServerReactor {
 
  private:
   friend class ServerCallbackReaderWriter<Request, Response>;
-  void BindStream(ServerCallbackReaderWriter<Request, Response>* stream) {
+  virtual void BindStream(
+      ServerCallbackReaderWriter<Request, Response>* stream) {
     stream_ = stream;
   }
 
@@ -358,7 +373,7 @@ class ServerReadReactor : public internal::ServerReactor {
   ///
   /// \param[in] context The context object now associated with this RPC
   /// \param[in] resp The response object to be used by this RPC
-  virtual void OnStarted(ServerContext* context, Response* resp) {}
+  virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {}
 
   /// The following notifications are exactly like ServerBidiReactor.
   virtual void OnSendInitialMetadataDone(bool ok) {}
@@ -368,7 +383,9 @@ class ServerReadReactor : public internal::ServerReactor {
 
  private:
   friend class ServerCallbackReader<Request>;
-  void BindReader(ServerCallbackReader<Request>* reader) { reader_ = reader; }
+  virtual void BindReader(ServerCallbackReader<Request>* reader) {
+    reader_ = reader;
+  }
 
   ServerCallbackReader<Request>* reader_;
 };
@@ -399,7 +416,8 @@ class ServerWriteReactor : public internal::ServerReactor {
   ///
   /// \param[in] context The context object now associated with this RPC
   /// \param[in] req The request object sent by the client
-  virtual void OnStarted(ServerContext* context, const Request* req) {}
+  virtual void OnStarted(::grpc_impl::ServerContext* context,
+                         const Request* req) {}
 
   /// The following notifications are exactly like ServerBidiReactor.
   virtual void OnSendInitialMetadataDone(bool ok) {}
@@ -409,7 +427,9 @@ class ServerWriteReactor : public internal::ServerReactor {
 
  private:
   friend class ServerCallbackWriter<Response>;
-  void BindWriter(ServerCallbackWriter<Response>* writer) { writer_ = writer; }
+  virtual void BindWriter(ServerCallbackWriter<Response>* writer) {
+    writer_ = writer;
+  }
 
   ServerCallbackWriter<Response>* writer_;
 };
@@ -423,7 +443,7 @@ class UnimplementedReadReactor
     : public experimental::ServerReadReactor<Request, Response> {
  public:
   void OnDone() override { delete this; }
-  void OnStarted(ServerContext*, Response*) override {
+  void OnStarted(::grpc_impl::ServerContext*, Response*) override {
     this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
   }
 };
@@ -433,7 +453,7 @@ class UnimplementedWriteReactor
     : public experimental::ServerWriteReactor<Request, Response> {
  public:
   void OnDone() override { delete this; }
-  void OnStarted(ServerContext*, const Request*) override {
+  void OnStarted(::grpc_impl::ServerContext*, const Request*) override {
     this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
   }
 };
@@ -443,7 +463,7 @@ class UnimplementedBidiReactor
     : public experimental::ServerBidiReactor<Request, Response> {
  public:
   void OnDone() override { delete this; }
-  void OnStarted(ServerContext*) override {
+  void OnStarted(::grpc_impl::ServerContext*) override {
     this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
   }
 };
@@ -452,7 +472,8 @@ template <class RequestType, class ResponseType>
 class CallbackUnaryHandler : public MethodHandler {
  public:
   CallbackUnaryHandler(
-      std::function<void(ServerContext*, const RequestType*, ResponseType*,
+      std::function<void(::grpc_impl::ServerContext*, const RequestType*,
+                         ResponseType*,
                          experimental::ServerCallbackRpcController*)>
           func)
       : func_(func) {}
@@ -465,13 +486,13 @@ class CallbackUnaryHandler : public MethodHandler {
   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* allocator_info =
-        static_cast<experimental::RpcAllocatorInfo<RequestType, ResponseType>*>(
+    auto* allocator_state =
+        static_cast<experimental::MessageHolder<RequestType, ResponseType>*>(
             param.internal_data);
     auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc(
         param.call->call(), sizeof(ServerCallbackRpcControllerImpl)))
         ServerCallbackRpcControllerImpl(param.server_context, param.call,
-                                        allocator_info, allocator_,
+                                        allocator_state,
                                         std::move(param.call_requester));
     Status status = param.status;
     if (status.ok()) {
@@ -489,42 +510,30 @@ class CallbackUnaryHandler : public MethodHandler {
     ByteBuffer buf;
     buf.set_buffer(req);
     RequestType* request = nullptr;
-    experimental::RpcAllocatorInfo<RequestType, ResponseType>* allocator_info =
-        new (g_core_codegen_interface->grpc_call_arena_alloc(
-            call, sizeof(*allocator_info)))
-            experimental::RpcAllocatorInfo<RequestType, ResponseType>();
+    experimental::MessageHolder<RequestType, ResponseType>* allocator_state =
+        nullptr;
     if (allocator_ != nullptr) {
-      allocator_->AllocateMessages(allocator_info);
+      allocator_state = allocator_->AllocateMessages();
     } else {
-      allocator_info->request =
-          new (g_core_codegen_interface->grpc_call_arena_alloc(
-              call, sizeof(RequestType))) RequestType();
-      allocator_info->response =
-          new (g_core_codegen_interface->grpc_call_arena_alloc(
-              call, sizeof(ResponseType))) ResponseType();
+      allocator_state = new (g_core_codegen_interface->grpc_call_arena_alloc(
+          call, sizeof(DefaultMessageHolder<RequestType, ResponseType>)))
+          DefaultMessageHolder<RequestType, ResponseType>();
     }
-    *handler_data = allocator_info;
-    request = allocator_info->request;
+    *handler_data = allocator_state;
+    request = allocator_state->request();
     *status = SerializationTraits<RequestType>::Deserialize(&buf, request);
     buf.Release();
     if (status->ok()) {
       return request;
     }
     // Clean up on deserialization failure.
-    if (allocator_ != nullptr) {
-      allocator_->DeallocateMessages(allocator_info);
-    } else {
-      allocator_info->request->~RequestType();
-      allocator_info->response->~ResponseType();
-      allocator_info->request = nullptr;
-      allocator_info->response = nullptr;
-    }
+    allocator_state->Release();
     return nullptr;
   }
 
  private:
-  std::function<void(ServerContext*, const RequestType*, ResponseType*,
-                     experimental::ServerCallbackRpcController*)>
+  std::function<void(::grpc_impl::ServerContext*, const RequestType*,
+                     ResponseType*, experimental::ServerCallbackRpcController*)>
       func_;
   experimental::MessageAllocator<RequestType, ResponseType>* allocator_ =
       nullptr;
@@ -548,9 +557,8 @@ class CallbackUnaryHandler : public MethodHandler {
       }
       // The response is dropped if the status is not OK.
       if (s.ok()) {
-        finish_ops_.ServerSendStatus(
-            &ctx_->trailing_metadata_,
-            finish_ops_.SendMessagePtr(allocator_info_->response));
+        finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
+                                     finish_ops_.SendMessagePtr(response()));
       } else {
         finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
       }
@@ -588,50 +596,32 @@ class CallbackUnaryHandler : public MethodHandler {
 
     void ClearCancelCallback() override { ctx_->ClearCancelCallback(); }
 
-    void FreeRequest() override {
-      if (allocator_ != nullptr) {
-        allocator_->DeallocateRequest(allocator_info_);
-      }
-    }
-
-    void* GetAllocatorState() override {
-      return allocator_info_->allocator_state;
+    experimental::RpcAllocatorState* GetRpcAllocatorState() override {
+      return allocator_state_;
     }
 
    private:
     friend class CallbackUnaryHandler<RequestType, ResponseType>;
 
     ServerCallbackRpcControllerImpl(
-        ServerContext* ctx, Call* call,
-        experimental::RpcAllocatorInfo<RequestType, ResponseType>*
-            allocator_info,
-        experimental::MessageAllocator<RequestType, ResponseType>* allocator,
+        ::grpc_impl::ServerContext* ctx, Call* call,
+        experimental::MessageHolder<RequestType, ResponseType>* allocator_state,
         std::function<void()> call_requester)
         : ctx_(ctx),
           call_(*call),
-          allocator_info_(allocator_info),
-          allocator_(allocator),
+          allocator_state_(allocator_state),
           call_requester_(std::move(call_requester)) {
       ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr);
     }
 
-    const RequestType* request() { return allocator_info_->request; }
-    ResponseType* response() { return allocator_info_->response; }
+    const RequestType* request() { return allocator_state_->request(); }
+    ResponseType* response() { return allocator_state_->response(); }
 
     void MaybeDone() {
       if (--callbacks_outstanding_ == 0) {
         grpc_call* call = call_.call();
         auto call_requester = std::move(call_requester_);
-        if (allocator_ != nullptr) {
-          allocator_->DeallocateMessages(allocator_info_);
-        } else {
-          if (allocator_info_->request != nullptr) {
-            allocator_info_->request->~RequestType();
-          }
-          if (allocator_info_->response != nullptr) {
-            allocator_info_->response->~ResponseType();
-          }
-        }
+        allocator_state_->Release();
         this->~ServerCallbackRpcControllerImpl();  // explicitly call destructor
         g_core_codegen_interface->grpc_call_unref(call);
         call_requester();
@@ -645,10 +635,10 @@ class CallbackUnaryHandler : public MethodHandler {
         finish_ops_;
     CallbackWithSuccessTag finish_tag_;
 
-    ServerContext* ctx_;
+    ::grpc_impl::ServerContext* ctx_;
     Call call_;
-    experimental::RpcAllocatorInfo<RequestType, ResponseType>* allocator_info_;
-    experimental::MessageAllocator<RequestType, ResponseType>* allocator_;
+    experimental::MessageHolder<RequestType, ResponseType>* const
+        allocator_state_;
     std::function<void()> call_requester_;
     std::atomic_int callbacks_outstanding_{
         2};  // reserve for Finish and CompletionOp
@@ -749,7 +739,8 @@ class CallbackClientStreamingHandler : public MethodHandler {
     friend class CallbackClientStreamingHandler<RequestType, ResponseType>;
 
     ServerCallbackReaderImpl(
-        ServerContext* ctx, Call* call, std::function<void()> call_requester,
+        ::grpc_impl::ServerContext* ctx, Call* call,
+        std::function<void()> call_requester,
         experimental::ServerReadReactor<RequestType, ResponseType>* reactor)
         : ctx_(ctx),
           call_(*call),
@@ -789,7 +780,7 @@ class CallbackClientStreamingHandler : public MethodHandler {
     CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
     CallbackWithSuccessTag read_tag_;
 
-    ServerContext* ctx_;
+    ::grpc_impl::ServerContext* ctx_;
     Call call_;
     ResponseType resp_;
     std::function<void()> call_requester_;
@@ -926,7 +917,7 @@ class CallbackServerStreamingHandler : public MethodHandler {
     friend class CallbackServerStreamingHandler<RequestType, ResponseType>;
 
     ServerCallbackWriterImpl(
-        ServerContext* ctx, Call* call, const RequestType* req,
+        ::grpc_impl::ServerContext* ctx, Call* call, const RequestType* req,
         std::function<void()> call_requester,
         experimental::ServerWriteReactor<RequestType, ResponseType>* reactor)
         : ctx_(ctx),
@@ -967,7 +958,7 @@ class CallbackServerStreamingHandler : public MethodHandler {
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
     CallbackWithSuccessTag write_tag_;
 
-    ServerContext* ctx_;
+    ::grpc_impl::ServerContext* ctx_;
     Call call_;
     const RequestType* req_;
     std::function<void()> call_requester_;
@@ -1095,7 +1086,8 @@ class CallbackBidiHandler : public MethodHandler {
     friend class CallbackBidiHandler<RequestType, ResponseType>;
 
     ServerCallbackReaderWriterImpl(
-        ServerContext* ctx, Call* call, std::function<void()> call_requester,
+        ::grpc_impl::ServerContext* ctx, Call* call,
+        std::function<void()> call_requester,
         experimental::ServerBidiReactor<RequestType, ResponseType>* reactor)
         : ctx_(ctx),
           call_(*call),
@@ -1141,7 +1133,7 @@ class CallbackBidiHandler : public MethodHandler {
     CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
     CallbackWithSuccessTag read_tag_;
 
-    ServerContext* ctx_;
+    ::grpc_impl::ServerContext* ctx_;
     Call call_;
     std::function<void()> call_requester_;
     experimental::ServerBidiReactor<RequestType, ResponseType>* reactor_;
index c690374..7ae1275 100644 (file)
 #ifndef GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
 #define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
 
-#include <map>
-#include <memory>
-#include <vector>
+#include <grpcpp/impl/codegen/server_context_impl.h>
 
-#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>
-
-struct grpc_metadata;
-struct grpc_call;
-struct census_context;
-
-namespace grpc_impl {
-
-class CompletionQueue;
-class Server;
-}  // namespace grpc_impl
 namespace grpc {
-class ClientContext;
-class GenericServerContext;
-class ServerInterface;
-template <class W, class R>
-class ServerAsyncReader;
-template <class W>
-class ServerAsyncWriter;
-template <class W>
-class ServerAsyncResponseWriter;
-template <class W, class R>
-class ServerAsyncReaderWriter;
-template <class R>
-class ServerReader;
-template <class W>
-class ServerWriter;
-
-namespace internal {
-template <class W, class R>
-class ServerReaderWriterBody;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler;
-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 ServerInterface;
-namespace testing {
-class InteropServerContextInspector;
-class ServerContextTestSpouse;
-}  // namespace testing
-
-/// A ServerContext allows the person implementing a service handler to:
-///
-/// - Add custom initial and trailing metadata key-value pairs that will
-///   propagated to the client side.
-/// - Control call settings such as compression and authentication.
-/// - Access metadata coming from the client.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call handler they are supplied to,
-/// that is to say, they aren't sticky across multiple calls. Some of these
-/// settings, such as the compression options, can be made persistent at server
-/// construction time by specifying the appropriate \a ChannelArguments
-/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
-///
-/// \warning ServerContext instances should \em not be reused across rpcs.
-class ServerContext {
- public:
-  ServerContext();  // for async calls
-  ~ServerContext();
-
-  /// Return the deadline for the server call.
-  std::chrono::system_clock::time_point deadline() const {
-    return Timespec2Timepoint(deadline_);
-  }
-
-  /// Return a \a gpr_timespec representation of the server call's deadline.
-  gpr_timespec raw_deadline() const { return deadline_; }
-
-  /// 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.
-  ///
-  /// \warning This method should only be called before sending initial metadata
-  /// to the client (which can happen explicitly, or implicitly when sending a
-  /// a response message or status to the client).
-  ///
-  /// \param key The metadata key. If \a value is binary data, it must
-  /// end in "-bin".
-  /// \param value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  ///
-  /// Metadata must conform to the following format:
-  /// Custom-Metadata -> Binary-Header / ASCII-Header
-  /// Binary-Header -> {Header-Name "-bin" } {binary value}
-  /// ASCII-Header -> Header-Name ASCII-Value
-  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
-  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
-  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
-
-  /// 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.
-  ///
-  /// \warning This method should only be called before sending trailing
-  /// metadata to the client (which happens when the call is finished and a
-  /// status is sent to the client).
-  ///
-  /// \param key The metadata key. If \a value is binary data,
-  /// it must end in "-bin".
-  /// \param value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  ///
-  /// Metadata must conform to the following format:
-  /// Custom-Metadata -> Binary-Header / ASCII-Header
-  /// Binary-Header -> {Header-Name "-bin" } {binary value}
-  /// ASCII-Header -> Header-Name ASCII-Value
-  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
-  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
-  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
-
-  /// 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;
-
-  /// Cancel the Call from the server. This is a best-effort API and
-  /// depending on when it is called, the RPC may still appear successful to
-  /// the client.
-  /// For example, if TryCancel() is called on a separate thread, it might race
-  /// with the server handler which might return success to the client before
-  /// TryCancel() was even started by the thread.
-  ///
-  /// It is the caller's responsibility to prevent such races and ensure that if
-  /// TryCancel() is called, the serverhandler must return Status::CANCELLED.
-  /// The only exception is that if the serverhandler is already returning an
-  /// error status code, it is ok to not return Status::CANCELLED even if
-  /// TryCancel() was called.
-  ///
-  /// Note that TryCancel() does not change any of the tags that are pending
-  /// on the completion queue. All pending tags will still be delivered
-  /// (though their ok result may reflect the effect of cancellation).
-  void TryCancel() const;
-
-  /// Return a collection of initial metadata key-value pairs sent from the
-  /// client. Note that keys may happen more than
-  /// once (ie, a \a std::multimap is returned).
-  ///
-  /// It is safe to use this method after initial metadata has been received,
-  /// Calls always begin with the client sending initial metadata, so this is
-  /// safe to access as soon as the call has begun on the server side.
-  ///
-  /// \return A multimap of initial metadata key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
-      const {
-    return *client_metadata_.map();
-  }
-
-  /// Return the compression algorithm to be used by the server call.
-  grpc_compression_level compression_level() const {
-    return compression_level_;
-  }
-
-  /// Set \a level to be the compression level 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;
-  }
-
-  /// Return a bool indicating whether the compression level for this call
-  /// has been set (either implicitly or through a previous call to
-  /// \a set_compression_level.
-  bool compression_level_set() const { return compression_level_set_; }
-
-  /// Return the compression algorithm the server call will request be used.
-  /// Note that the gRPC runtime may decide to ignore this request, for example,
-  /// due to resource constraints, or if the server is aware the client doesn't
-  /// support the requested algorithm.
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-  /// Set \a algorithm to be the compression algorithm used for the server call.
-  ///
-  /// \param algorithm The compression algorithm used for the server call.
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  /// Set the serialized load reporting costs in \a cost_data for the call.
-  void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
-
-  /// Return the authentication context for this server call.
-  ///
-  /// \see grpc::AuthContext.
-  std::shared_ptr<const AuthContext> auth_context() const {
-    if (auth_context_.get() == nullptr) {
-      auth_context_ = CreateAuthContext(call_);
-    }
-    return auth_context_;
-  }
-
-  /// Return the peer uri in a string.
-  /// WARNING: this value is never authenticated or subject to any security
-  /// related code. It must not be used for any authentication related
-  /// functionality. Instead, use auth_context.
-  grpc::string peer() const;
-
-  /// Get the census context associated with this server call.
-  const struct census_context* census_context() const;
-
-  /// Async only. Has to be called before the rpc starts.
-  /// Returns the tag in completion queue when the rpc finishes.
-  /// IsCancelled() can then be called to check whether the rpc was cancelled.
-  /// TODO(vjpai): Fix this so that the tag is returned even if the call never
-  /// starts (https://github.com/grpc/grpc/issues/10136).
-  void AsyncNotifyWhenDone(void* tag) {
-    has_notify_when_done_tag_ = true;
-    async_notify_when_done_tag_ = tag;
-  }
-
-  /// Should be used for framework-level extensions only.
-  /// Applications never need to call this method.
-  grpc_call* c_call() { return call_; }
-
- private:
-  friend class ::grpc::testing::InteropServerContextInspector;
-  friend class ::grpc::testing::ServerContextTestSpouse;
-  friend class ::grpc::ServerInterface;
-  friend class ::grpc_impl::Server;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReader;
-  template <class W>
-  friend class ::grpc::ServerAsyncWriter;
-  template <class W>
-  friend class ::grpc::ServerAsyncResponseWriter;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ServerReader;
-  template <class W>
-  friend class ::grpc::ServerWriter;
-  template <class W, class R>
-  friend class ::grpc::internal::ServerReaderWriterBody;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::ClientStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  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;
-  friend class ::grpc::GenericServerContext;
-
-  /// Prevent copying.
-  ServerContext(const ServerContext&);
-  ServerContext& operator=(const ServerContext&);
-
-  class CompletionOp;
-
-  void BeginCompletionOp(internal::Call* call,
-                         std::function<void(bool)> callback,
-                         internal::ServerReactor* reactor);
-  /// Return the tag queued by BeginCompletionOp()
-  internal::CompletionQueueTag* GetCompletionOpTag();
-
-  ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
-
-  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; }
-
-  void SetCancelCallback(std::function<void()> callback);
-  void ClearCancelCallback();
-
-  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_;
-  ::grpc_impl::CompletionQueue* cq_;
-  bool sent_initial_metadata_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  mutable internal::MetadataMap client_metadata_;
-  std::multimap<grpc::string, grpc::string> initial_metadata_;
-  std::multimap<grpc::string, grpc::string> trailing_metadata_;
-
-  bool compression_level_set_;
-  grpc_compression_level compression_level_;
-  grpc_compression_algorithm compression_algorithm_;
-
-  internal::CallOpSet<internal::CallOpSendInitialMetadata,
-                      internal::CallOpSendMessage>
-      pending_ops_;
-  bool has_pending_ops_;
-
-  experimental::ServerRpcInfo* rpc_info_;
-};
-
+typedef ::grpc_impl::ServerContext ServerContext;
 }  // namespace grpc
 
 #endif  // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
diff --git a/include/grpcpp/impl/codegen/server_context_impl.h b/include/grpcpp/impl/codegen/server_context_impl.h
new file mode 100644 (file)
index 0000000..9497735
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ *
+ * Copyright 2019 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_CONTEXT_IMPL_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
+#include <map>
+#include <memory>
+#include <vector>
+
+#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>
+
+struct grpc_metadata;
+struct grpc_call;
+struct census_context;
+
+namespace grpc_impl {
+class ClientContext;
+class CompletionQueue;
+class Server;
+}  // namespace grpc_impl
+namespace grpc {
+class GenericServerContext;
+class ServerInterface;
+template <class W, class R>
+class ServerAsyncReader;
+template <class W>
+class ServerAsyncWriter;
+template <class W>
+class ServerAsyncResponseWriter;
+template <class W, class R>
+class ServerAsyncReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+
+namespace internal {
+template <class W, class R>
+class ServerReaderWriterBody;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+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 ServerInterface;
+namespace testing {
+class InteropServerContextInspector;
+class ServerContextTestSpouse;
+}  // namespace testing
+}  // namespace grpc
+
+namespace grpc_impl {
+/// A ServerContext allows the person implementing a service handler to:
+///
+/// - Add custom initial and trailing metadata key-value pairs that will
+///   propagated to the client side.
+/// - Control call settings such as compression and authentication.
+/// - Access metadata coming from the client.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call handler they are supplied to,
+/// that is to say, they aren't sticky across multiple calls. Some of these
+/// settings, such as the compression options, can be made persistent at server
+/// construction time by specifying the appropriate \a ChannelArguments
+/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
+///
+/// \warning ServerContext instances should \em not be reused across rpcs.
+class ServerContext {
+ public:
+  ServerContext();  // for async calls
+  ~ServerContext();
+
+  /// Return the deadline for the server call.
+  std::chrono::system_clock::time_point deadline() const {
+    return ::grpc::Timespec2Timepoint(deadline_);
+  }
+
+  /// Return a \a gpr_timespec representation of the server call's deadline.
+  gpr_timespec raw_deadline() const { return deadline_; }
+
+  /// 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.
+  ///
+  /// \warning This method should only be called before sending initial metadata
+  /// to the client (which can happen explicitly, or implicitly when sending a
+  /// a response message or status to the client).
+  ///
+  /// \param key The metadata key. If \a value is binary data, it must
+  /// end in "-bin".
+  /// \param value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  ///
+  /// Metadata must conform to the following format:
+  /// Custom-Metadata -> Binary-Header / ASCII-Header
+  /// Binary-Header -> {Header-Name "-bin" } {binary value}
+  /// ASCII-Header -> Header-Name ASCII-Value
+  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
+  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
+  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
+
+  /// 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.
+  ///
+  /// \warning This method should only be called before sending trailing
+  /// metadata to the client (which happens when the call is finished and a
+  /// status is sent to the client).
+  ///
+  /// \param key The metadata key. If \a value is binary data,
+  /// it must end in "-bin".
+  /// \param value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  ///
+  /// Metadata must conform to the following format:
+  /// Custom-Metadata -> Binary-Header / ASCII-Header
+  /// Binary-Header -> {Header-Name "-bin" } {binary value}
+  /// ASCII-Header -> Header-Name ASCII-Value
+  /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
+  /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
+  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
+
+  /// 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;
+
+  /// Cancel the Call from the server. This is a best-effort API and
+  /// depending on when it is called, the RPC may still appear successful to
+  /// the client.
+  /// For example, if TryCancel() is called on a separate thread, it might race
+  /// with the server handler which might return success to the client before
+  /// TryCancel() was even started by the thread.
+  ///
+  /// It is the caller's responsibility to prevent such races and ensure that if
+  /// TryCancel() is called, the serverhandler must return Status::CANCELLED.
+  /// The only exception is that if the serverhandler is already returning an
+  /// error status code, it is ok to not return Status::CANCELLED even if
+  /// TryCancel() was called.
+  ///
+  /// Note that TryCancel() does not change any of the tags that are pending
+  /// on the completion queue. All pending tags will still be delivered
+  /// (though their ok result may reflect the effect of cancellation).
+  void TryCancel() const;
+
+  /// Return a collection of initial metadata key-value pairs sent from the
+  /// client. Note that keys may happen more than
+  /// once (ie, a \a std::multimap is returned).
+  ///
+  /// It is safe to use this method after initial metadata has been received,
+  /// Calls always begin with the client sending initial metadata, so this is
+  /// safe to access as soon as the call has begun on the server side.
+  ///
+  /// \return A multimap of initial metadata key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
+      const {
+    return *client_metadata_.map();
+  }
+
+  /// Return the compression algorithm to be used by the server call.
+  grpc_compression_level compression_level() const {
+    return compression_level_;
+  }
+
+  /// Set \a level to be the compression level 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;
+  }
+
+  /// Return a bool indicating whether the compression level for this call
+  /// has been set (either implicitly or through a previous call to
+  /// \a set_compression_level.
+  bool compression_level_set() const { return compression_level_set_; }
+
+  /// Return the compression algorithm the server call will request be used.
+  /// Note that the gRPC runtime may decide to ignore this request, for example,
+  /// due to resource constraints, or if the server is aware the client doesn't
+  /// support the requested algorithm.
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+  /// Set \a algorithm to be the compression algorithm used for the server call.
+  ///
+  /// \param algorithm The compression algorithm used for the server call.
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  /// Set the serialized load reporting costs in \a cost_data for the call.
+  void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
+
+  /// Return the authentication context for this server call.
+  ///
+  /// \see grpc::AuthContext.
+  std::shared_ptr<const ::grpc::AuthContext> auth_context() const {
+    if (auth_context_.get() == nullptr) {
+      auth_context_ = ::grpc::CreateAuthContext(call_);
+    }
+    return auth_context_;
+  }
+
+  /// Return the peer uri in a string.
+  /// WARNING: this value is never authenticated or subject to any security
+  /// related code. It must not be used for any authentication related
+  /// functionality. Instead, use auth_context.
+  grpc::string peer() const;
+
+  /// Get the census context associated with this server call.
+  const struct census_context* census_context() const;
+
+  /// Async only. Has to be called before the rpc starts.
+  /// Returns the tag in completion queue when the rpc finishes.
+  /// IsCancelled() can then be called to check whether the rpc was cancelled.
+  /// TODO(vjpai): Fix this so that the tag is returned even if the call never
+  /// starts (https://github.com/grpc/grpc/issues/10136).
+  void AsyncNotifyWhenDone(void* tag) {
+    has_notify_when_done_tag_ = true;
+    async_notify_when_done_tag_ = tag;
+  }
+
+  /// Should be used for framework-level extensions only.
+  /// Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
+ private:
+  friend class ::grpc::testing::InteropServerContextInspector;
+  friend class ::grpc::testing::ServerContextTestSpouse;
+  friend class ::grpc::ServerInterface;
+  friend class ::grpc_impl::Server;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReader;
+  template <class W>
+  friend class ::grpc::ServerAsyncWriter;
+  template <class W>
+  friend class ::grpc::ServerAsyncResponseWriter;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ServerReader;
+  template <class W>
+  friend class ::grpc::ServerWriter;
+  template <class W, class R>
+  friend class ::grpc::internal::ServerReaderWriterBody;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  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 <::grpc::StatusCode code>
+  friend class ::grpc::internal::ErrorMethodHandler;
+  friend class ::grpc_impl::ClientContext;
+  friend class ::grpc::GenericServerContext;
+
+  /// Prevent copying.
+  ServerContext(const ServerContext&);
+  ServerContext& operator=(const ServerContext&);
+
+  class CompletionOp;
+
+  void BeginCompletionOp(::grpc::internal::Call* call,
+                         std::function<void(bool)> callback,
+                         ::grpc::internal::ServerReactor* reactor);
+  /// Return the tag queued by BeginCompletionOp()
+  ::grpc::internal::CompletionQueueTag* GetCompletionOpTag();
+
+  ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
+
+  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; }
+
+  void SetCancelCallback(std::function<void()> callback);
+  void ClearCancelCallback();
+
+  ::grpc::experimental::ServerRpcInfo* set_server_rpc_info(
+      const char* method, ::grpc::internal::RpcMethod::RpcType type,
+      const std::vector<std::unique_ptr<
+          ::grpc::experimental::ServerInterceptorFactoryInterface>>& creators) {
+    if (creators.size() != 0) {
+      rpc_info_ = new ::grpc::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_;
+  ::grpc::internal::CallbackWithSuccessTag completion_tag_;
+
+  gpr_timespec deadline_;
+  grpc_call* call_;
+  ::grpc_impl::CompletionQueue* cq_;
+  bool sent_initial_metadata_;
+  mutable std::shared_ptr<const ::grpc::AuthContext> auth_context_;
+  mutable ::grpc::internal::MetadataMap client_metadata_;
+  std::multimap<grpc::string, grpc::string> initial_metadata_;
+  std::multimap<grpc::string, grpc::string> trailing_metadata_;
+
+  bool compression_level_set_;
+  grpc_compression_level compression_level_;
+  grpc_compression_algorithm compression_algorithm_;
+
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage>
+      pending_ops_;
+  bool has_pending_ops_;
+
+  ::grpc::experimental::ServerRpcInfo* rpc_info_;
+};
+}  // namespace grpc_impl
+#endif  // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
index 8875a28..28fdc27 100644 (file)
 #include <grpcpp/impl/codegen/rpc_method.h>
 #include <grpcpp/impl/codegen/string_ref.h>
 
-namespace grpc {
-
+namespace grpc_impl {
 class ServerContext;
+}
+
+namespace grpc {
 
 namespace internal {
 class InterceptorBatchMethodsImpl;
@@ -78,7 +80,7 @@ class ServerRpcInfo {
 
   /// Return a pointer to the underlying ServerContext structure associated
   /// with the RPC to support features that apply to it
-  grpc::ServerContext* server_context() { return ctx_; }
+  grpc_impl::ServerContext* server_context() { return ctx_; }
 
  private:
   static_assert(Type::UNARY ==
@@ -94,7 +96,7 @@ class ServerRpcInfo {
                     static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
                 "violated expectation about Type enum");
 
-  ServerRpcInfo(grpc::ServerContext* ctx, const char* method,
+  ServerRpcInfo(grpc_impl::ServerContext* ctx, const char* method,
                 internal::RpcMethod::RpcType type)
       : ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {
     ref_.store(1);
@@ -127,14 +129,14 @@ class ServerRpcInfo {
     }
   }
 
-  grpc::ServerContext* ctx_ = nullptr;
+  grpc_impl::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;
+  friend class grpc_impl::ServerContext;
 };
 
 }  // namespace experimental
index 10dc6ab..9600e5f 100644 (file)
 
 namespace grpc_impl {
 
+class Channel;
 class CompletionQueue;
 class ServerCompletionQueue;
-class Channel;
 class ServerCredentials;
+class ServerContext;
 }  // namespace grpc_impl
 namespace grpc {
 
 class AsyncGenericService;
 class GenericServerContext;
-class ServerContext;
 class Service;
 
 extern CoreCodegenInterface* g_core_codegen_interface;
@@ -176,7 +176,8 @@ class ServerInterface : public internal::CallHook {
 
   class BaseAsyncRequest : public internal::CompletionQueueTag {
    public:
-    BaseAsyncRequest(ServerInterface* server, ServerContext* context,
+    BaseAsyncRequest(ServerInterface* server,
+                     ::grpc_impl::ServerContext* context,
                      internal::ServerAsyncStreamingInterface* stream,
                      ::grpc_impl::CompletionQueue* call_cq,
                      ::grpc_impl::ServerCompletionQueue* notification_cq,
@@ -190,7 +191,7 @@ class ServerInterface : public internal::CallHook {
 
    protected:
     ServerInterface* const server_;
-    ServerContext* const context_;
+    ::grpc_impl::ServerContext* const context_;
     internal::ServerAsyncStreamingInterface* const stream_;
     ::grpc_impl::CompletionQueue* const call_cq_;
     ::grpc_impl::ServerCompletionQueue* const notification_cq_;
@@ -205,7 +206,8 @@ class ServerInterface : public internal::CallHook {
   /// RegisteredAsyncRequest is not part of the C++ API
   class RegisteredAsyncRequest : public BaseAsyncRequest {
    public:
-    RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
+    RegisteredAsyncRequest(ServerInterface* server,
+                           ::grpc_impl::ServerContext* context,
                            internal::ServerAsyncStreamingInterface* stream,
                            ::grpc_impl::CompletionQueue* call_cq,
                            ::grpc_impl::ServerCompletionQueue* notification_cq,
@@ -234,7 +236,8 @@ class ServerInterface : public internal::CallHook {
   class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
    public:
     NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
-                          ServerInterface* server, ServerContext* context,
+                          ServerInterface* server,
+                          ::grpc_impl::ServerContext* context,
                           internal::ServerAsyncStreamingInterface* stream,
                           ::grpc_impl::CompletionQueue* call_cq,
                           ::grpc_impl::ServerCompletionQueue* notification_cq,
@@ -252,7 +255,8 @@ class ServerInterface : public internal::CallHook {
   class PayloadAsyncRequest final : public RegisteredAsyncRequest {
    public:
     PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
-                        ServerInterface* server, ServerContext* context,
+                        ServerInterface* server,
+                        ::grpc_impl::ServerContext* context,
                         internal::ServerAsyncStreamingInterface* stream,
                         ::grpc_impl::CompletionQueue* call_cq,
                         ::grpc_impl::ServerCompletionQueue* notification_cq,
@@ -309,7 +313,7 @@ class ServerInterface : public internal::CallHook {
    private:
     internal::RpcServiceMethod* const registered_method_;
     ServerInterface* const server_;
-    ServerContext* const context_;
+    ::grpc_impl::ServerContext* const context_;
     internal::ServerAsyncStreamingInterface* const stream_;
     ::grpc_impl::CompletionQueue* const call_cq_;
 
@@ -335,7 +339,7 @@ class ServerInterface : public internal::CallHook {
 
   template <class Message>
   void RequestAsyncCall(internal::RpcServiceMethod* method,
-                        ServerContext* context,
+                        ::grpc_impl::ServerContext* context,
                         internal::ServerAsyncStreamingInterface* stream,
                         ::grpc_impl::CompletionQueue* call_cq,
                         ::grpc_impl::ServerCompletionQueue* notification_cq,
@@ -346,7 +350,7 @@ class ServerInterface : public internal::CallHook {
   }
 
   void RequestAsyncCall(internal::RpcServiceMethod* method,
-                        ServerContext* context,
+                        ::grpc_impl::ServerContext* context,
                         internal::ServerAsyncStreamingInterface* stream,
                         ::grpc_impl::CompletionQueue* call_cq,
                         ::grpc_impl::ServerCompletionQueue* notification_cq,
index f1d1272..4109ee1 100644 (file)
@@ -30,11 +30,11 @@ namespace grpc_impl {
 
 class Server;
 class CompletionQueue;
+class ServerContext;
 }  // namespace grpc_impl
 namespace grpc {
 
 class ServerInterface;
-class ServerContext;
 
 namespace internal {
 class Call;
@@ -146,7 +146,8 @@ class Service {
   experimental_type experimental() { return experimental_type(this); }
 
   template <class Message>
-  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
+  void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context,
+                         Message* request,
                          internal::ServerAsyncStreamingInterface* stream,
                          CompletionQueue* call_cq,
                          ServerCompletionQueue* notification_cq, void* tag) {
@@ -158,7 +159,7 @@ class Service {
                               notification_cq, tag, request);
   }
   void RequestAsyncClientStreaming(
-      int index, ServerContext* context,
+      int index, ::grpc_impl::ServerContext* context,
       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
       ServerCompletionQueue* notification_cq, void* tag) {
     size_t idx = static_cast<size_t>(index);
@@ -167,7 +168,7 @@ class Service {
   }
   template <class Message>
   void RequestAsyncServerStreaming(
-      int index, ServerContext* context, Message* request,
+      int index, ::grpc_impl::ServerContext* context, Message* request,
       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
       ServerCompletionQueue* notification_cq, void* tag) {
     size_t idx = static_cast<size_t>(index);
@@ -175,7 +176,7 @@ class Service {
                               notification_cq, tag, request);
   }
   void RequestAsyncBidiStreaming(
-      int index, ServerContext* context,
+      int index, ::grpc_impl::ServerContext* context,
       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
       ServerCompletionQueue* notification_cq, void* tag) {
     size_t idx = static_cast<size_t>(index);
index 14c6add..39bac6b 100644 (file)
@@ -30,7 +30,7 @@ static inline void RegisterOpenCensusViewsForExport() {
   ::grpc_impl::RegisterOpenCensusViewsForExport();
 }
 static inline ::opencensus::trace::Span GetSpanFromServerContext(
-    ServerContext* context) {
+    ::grpc_impl::ServerContext* context) {
   return ::grpc_impl::GetSpanFromServerContext(context);
 }
 
index 631d2b8..dbcb7c9 100644 (file)
 
 #include "opencensus/trace/span.h"
 
-namespace grpc {
-
-class ServerContext;
-}
 namespace grpc_impl {
+class ServerContext;
 // These symbols in this file will not be included in the binary unless
 // grpc_opencensus_plugin build target was added as a dependency. At the moment
 // it is only setup to be built with Bazel.
@@ -43,8 +40,7 @@ void RegisterOpenCensusPlugin();
 void RegisterOpenCensusViewsForExport();
 
 // Returns the tracing Span for the current RPC.
-::opencensus::trace::Span GetSpanFromServerContext(
-    grpc::ServerContext* context);
+::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context);
 
 }  // namespace grpc_impl
 
index 57f8dc0..7f85e80 100644 (file)
@@ -44,19 +44,42 @@ class Server;
 class ServerCompletionQueue;
 class ServerCredentials;
 }  // namespace grpc_impl
+
 namespace grpc {
 
 class AsyncGenericService;
 class Service;
-
 namespace testing {
 class ServerBuilderPluginTest;
 }  // namespace testing
 
+namespace internal {
+class ExternalConnectionAcceptorImpl;
+}  // namespace internal
+
 namespace experimental {
 class CallbackGenericService;
-}
+
+// EXPERIMENTAL API:
+// Interface for a grpc server to build transports with connections created out
+// of band.
+// See ServerBuilder's AddExternalConnectionAcceptor API.
+class ExternalConnectionAcceptor {
+ public:
+  struct NewConnectionParameters {
+    int listener_fd = -1;
+    int fd = -1;
+    ByteBuffer read_buffer;  // data intended for the grpc server
+  };
+  virtual ~ExternalConnectionAcceptor() {}
+  // If called before grpc::Server is started or after it is shut down, the new
+  // connection will be closed.
+  virtual void HandleNewConnection(NewConnectionParameters* p) = 0;
+};
+
+}  // namespace experimental
 }  // namespace grpc
+
 namespace grpc_impl {
 
 /// A builder class for the creation and startup of \a grpc::Server instances.
@@ -249,6 +272,18 @@ class ServerBuilder {
     ServerBuilder& RegisterCallbackGenericService(
         grpc::experimental::CallbackGenericService* service);
 
+    enum class ExternalConnectionType {
+      FROM_FD = 0  // in the form of a file descriptor
+    };
+
+    /// Register an acceptor to handle the externally accepted connection in
+    /// grpc server. The returned acceptor can be used to pass the connection
+    /// to grpc server, where a channel will be created with the provided
+    /// server credentials.
+    std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
+    AddExternalConnectionAcceptor(ExternalConnectionType type,
+                                  std::shared_ptr<ServerCredentials> creds);
+
    private:
     ServerBuilder* builder_;
   };
@@ -348,6 +383,8 @@ class ServerBuilder {
   std::vector<
       std::unique_ptr<grpc::experimental::ServerInterceptorFactoryInterface>>
       interceptor_creators_;
+  std::vector<std::shared_ptr<grpc::internal::ExternalConnectionAcceptorImpl>>
+      acceptors_;
 };
 
 }  // namespace grpc_impl
index 2a53265..90019e2 100644 (file)
 struct grpc_server;
 
 namespace grpc {
-
 class AsyncGenericService;
-class ServerContext;
+
+namespace internal {
+class ExternalConnectionAcceptorImpl;
+}  // namespace internal
 
 }  // namespace grpc
 
 namespace grpc_impl {
-
+class HealthCheckServiceInterface;
+class ServerContext;
 class ServerInitializer;
 
 /// Represents a gRPC server.
@@ -79,9 +82,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
     /// Called before server is created.
     virtual void UpdateArguments(grpc::ChannelArguments* args) {}
     /// Called before application callback for each synchronous server request
-    virtual void PreSynchronousRequest(grpc::ServerContext* context) = 0;
+    virtual void PreSynchronousRequest(grpc_impl::ServerContext* context) = 0;
     /// Called after application callback for each synchronous server request
-    virtual void PostSynchronousRequest(grpc::ServerContext* context) = 0;
+    virtual void PostSynchronousRequest(grpc_impl::ServerContext* context) = 0;
     /// Called before server is started.
     virtual void PreServerStart(Server* server) {}
     /// Called after a server port is added.
@@ -184,6 +187,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
       std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
           sync_server_cqs,
       int min_pollers, int max_pollers, int sync_cq_timeout_msec,
+      std::vector<
+          std::shared_ptr<grpc::internal::ExternalConnectionAcceptorImpl>>
+          acceptors,
       grpc_resource_quota* server_rq = nullptr,
       std::vector<std::unique_ptr<
           grpc::experimental::ServerInterceptorFactoryInterface>>
@@ -200,6 +206,18 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
 
   grpc_server* server() override { return server_; }
 
+ protected:
+  /// NOTE: This method is not part of the public API for this class.
+  void set_health_check_service(
+      std::unique_ptr<grpc::HealthCheckServiceInterface> service) {
+    health_check_service_ = std::move(service);
+  }
+
+  /// NOTE: This method is not part of the public API for this class.
+  bool health_check_service_disabled() const {
+    return health_check_service_disabled_;
+  }
+
  private:
   std::vector<
       std::unique_ptr<grpc::experimental::ServerInterceptorFactoryInterface>>*
@@ -269,6 +287,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
 
   grpc_impl::ServerInitializer* initializer();
 
+  std::vector<std::shared_ptr<grpc::internal::ExternalConnectionAcceptorImpl>>
+      acceptors_;
+
   // A vector of interceptor factory objects.
   // This should be destroyed after health_check_service_ and this requirement
   // is satisfied by declaring interceptor_creators_ before
index 0efeadc..ac3b6c4 100644 (file)
@@ -61,8 +61,8 @@ class ChannelArguments {
   void SetChannelArgs(grpc_channel_args* channel_args) const;
 
   // gRPC specific channel argument setters
-  /// Set target name override for SSL host name checking. This option is for
-  /// testing only and should never be used in production.
+  /// Set target name override for SSL host name checking. This option should
+  /// be used with caution in production.
   void SetSslTargetNameOverride(const grpc::string& name);
   // TODO(yangg) add flow control options
   /// Set the compression algorithm for the channel.
diff --git a/include/grpcpp/support/validate_service_config.h b/include/grpcpp/support/validate_service_config.h
new file mode 100644 (file)
index 0000000..41f2c63
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2019 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_VALIDATE_SERVICE_CONFIG_H
+#define GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
+
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+
+namespace experimental {
+/// Validates \a service_config_json. If valid, returns an empty string.
+/// Otherwise, returns the validation error.
+/// TODO(yashykt): Promote it to out of experimental once it is proved useful
+/// and gRFC is accepted.
+grpc::string ValidateServiceConfigJSON(const grpc::string& service_config_json);
+}  // namespace experimental
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
index f03c4e6..0314e89 100644 (file)
@@ -13,8 +13,8 @@
  <date>2018-01-19</date>
  <time>16:06:07</time>
  <version>
-  <release>1.21.3</release>
-  <api>1.21.3</api>
+  <release>1.22.0</release>
+  <api>1.22.0</api>
  </version>
  <stability>
   <release>stable</release>
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/server_address.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/service_config.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_interface.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_pool_interface.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/lib/slice/slice_hash_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/slice/slice_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_weak_hash_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
index e978437..4d52beb 100644 (file)
@@ -1,6 +1,6 @@
 # GRPC Python setup requirements
 coverage>=4.0
-cython==0.28.3
+cython>=0.29.8
 enum34>=1.0.4
 protobuf>=3.5.0.post1
 six>=1.10
index 6c97824..27dd7d9 100644 (file)
@@ -1,6 +1,6 @@
 # GRPC Python setup requirements
 coverage>=4.0
-cython==0.28.3
+cython>=0.29.8
 enum34>=1.0.4
 protobuf>=3.5.0.post1
 six>=1.10
index 77cd7b5..23e3bd5 100644 (file)
@@ -155,18 +155,15 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
                   params.grpc_search_path);
     printer->Print(vars, "\n");
     printer->Print(vars, "namespace grpc_impl {\n");
-    printer->Print(vars, "class Channel;\n");
     printer->Print(vars, "class CompletionQueue;\n");
     printer->Print(vars, "class ServerCompletionQueue;\n");
+    printer->Print(vars, "class ServerContext;\n");
     printer->Print(vars, "}  // namespace grpc_impl\n\n");
     printer->Print(vars, "namespace grpc {\n");
     printer->Print(vars, "namespace experimental {\n");
     printer->Print(vars, "template <typename RequestT, typename ResponseT>\n");
     printer->Print(vars, "class MessageAllocator;\n");
     printer->Print(vars, "}  // namespace experimental\n");
-    printer->Print(vars, "}  // namespace grpc_impl\n\n");
-    printer->Print(vars, "namespace grpc {\n");
-    printer->Print(vars, "class ServerContext;\n");
     printer->Print(vars, "}  // namespace grpc\n\n");
 
     vars["message_header_ext"] = params.message_header_extension.empty()
index 778e5c3..a45408a 100644 (file)
@@ -414,24 +414,34 @@ void GenerateServerClass(Printer* out, const ServiceDescriptor* service) {
   out->Print("\n");
 }
 
-void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
-  out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename",
-             GetServiceClassName(service));
-  out->Print("public partial class $name$ : grpc::ClientBase<$name$>\n", "name",
-             GetClientClassName(service));
+void GenerateClientStub(Printer* out, const ServiceDescriptor* service,
+                        bool lite_client) {
+  if (!lite_client) {
+    out->Print("/// <summary>Client for $servicename$</summary>\n",
+               "servicename", GetServiceClassName(service));
+    out->Print("public partial class $name$ : grpc::ClientBase<$name$>\n",
+               "name", GetClientClassName(service));
+  } else {
+    out->Print("/// <summary>Lite client for $servicename$</summary>\n",
+               "servicename", GetServiceClassName(service));
+    out->Print("public partial class $name$ : grpc::LiteClientBase\n", "name",
+               GetClientClassName(service));
+  }
   out->Print("{\n");
   out->Indent();
 
   // constructors
-  out->Print(
-      "/// <summary>Creates a new client for $servicename$</summary>\n"
-      "/// <param name=\"channel\">The channel to use to make remote "
-      "calls.</param>\n",
-      "servicename", GetServiceClassName(service));
-  out->Print("public $name$(grpc::Channel channel) : base(channel)\n", "name",
-             GetClientClassName(service));
-  out->Print("{\n");
-  out->Print("}\n");
+  if (!lite_client) {
+    out->Print(
+        "/// <summary>Creates a new client for $servicename$</summary>\n"
+        "/// <param name=\"channel\">The channel to use to make remote "
+        "calls.</param>\n",
+        "servicename", GetServiceClassName(service));
+    out->Print("public $name$(grpc::Channel channel) : base(channel)\n", "name",
+               GetClientClassName(service));
+    out->Print("{\n");
+    out->Print("}\n");
+  }
   out->Print(
       "/// <summary>Creates a new client for $servicename$ that uses a custom "
       "<c>CallInvoker</c>.</summary>\n"
@@ -450,16 +460,20 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
              GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n");
-  out->Print(
-      "/// <summary>Protected constructor to allow creation of configured "
-      "clients.</summary>\n"
-      "/// <param name=\"configuration\">The client configuration.</param>\n");
-  out->Print(
-      "protected $name$(ClientBaseConfiguration configuration)"
-      " : base(configuration)\n",
-      "name", GetClientClassName(service));
-  out->Print("{\n");
-  out->Print("}\n\n");
+  if (!lite_client) {
+    out->Print(
+        "/// <summary>Protected constructor to allow creation of configured "
+        "clients.</summary>\n"
+        "/// <param name=\"configuration\">The client "
+        "configuration.</param>\n");
+    out->Print(
+        "protected $name$(ClientBaseConfiguration configuration)"
+        " : base(configuration)\n",
+        "name", GetClientClassName(service));
+    out->Print("{\n");
+    out->Print("}\n");
+  }
+  out->Print("\n");
 
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor* method = service->method(i);
@@ -577,19 +591,21 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
   }
 
   // override NewInstance method
-  out->Print(
-      "/// <summary>Creates a new instance of client from given "
-      "<c>ClientBaseConfiguration</c>.</summary>\n");
-  out->Print(
-      "protected override $name$ NewInstance(ClientBaseConfiguration "
-      "configuration)\n",
-      "name", GetClientClassName(service));
-  out->Print("{\n");
-  out->Indent();
-  out->Print("return new $name$(configuration);\n", "name",
-             GetClientClassName(service));
-  out->Outdent();
-  out->Print("}\n");
+  if (!lite_client) {
+    out->Print(
+        "/// <summary>Creates a new instance of client from given "
+        "<c>ClientBaseConfiguration</c>.</summary>\n");
+    out->Print(
+        "protected override $name$ NewInstance(ClientBaseConfiguration "
+        "configuration)\n",
+        "name", GetClientClassName(service));
+    out->Print("{\n");
+    out->Indent();
+    out->Print("return new $name$(configuration);\n", "name",
+               GetClientClassName(service));
+    out->Outdent();
+    out->Print("}\n");
+  }
 
   out->Outdent();
   out->Print("}\n");
@@ -671,7 +687,7 @@ void GenerateBindServiceWithBinderMethod(Printer* out,
 
 void GenerateService(Printer* out, const ServiceDescriptor* service,
                      bool generate_client, bool generate_server,
-                     bool internal_access) {
+                     bool internal_access, bool lite_client) {
   GenerateDocCommentBody(out, service);
   out->Print("$access_level$ static partial class $classname$\n",
              "access_level", GetAccessLevel(internal_access), "classname",
@@ -693,8 +709,9 @@ void GenerateService(Printer* out, const ServiceDescriptor* service,
     GenerateServerClass(out, service);
   }
   if (generate_client) {
-    GenerateClientStub(out, service);
+    GenerateClientStub(out, service, lite_client);
   }
+
   if (generate_server) {
     GenerateBindServiceMethod(out, service);
     GenerateBindServiceWithBinderMethod(out, service);
@@ -707,7 +724,8 @@ void GenerateService(Printer* out, const ServiceDescriptor* service,
 }  // anonymous namespace
 
 grpc::string GetServices(const FileDescriptor* file, bool generate_client,
-                         bool generate_server, bool internal_access) {
+                         bool generate_server, bool internal_access,
+                         bool lite_client) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -749,7 +767,7 @@ grpc::string GetServices(const FileDescriptor* file, bool generate_client,
     }
     for (int i = 0; i < file->service_count(); i++) {
       GenerateService(&out, file->service(i), generate_client, generate_server,
-                      internal_access);
+                      internal_access, lite_client);
     }
     if (file_namespace != "") {
       out.Outdent();
index fd36e11..d4c13c6 100644 (file)
@@ -27,7 +27,7 @@ namespace grpc_csharp_generator {
 
 grpc::string GetServices(const grpc::protobuf::FileDescriptor* file,
                          bool generate_client, bool generate_server,
-                         bool internal_access);
+                         bool internal_access, bool lite_client);
 
 }  // namespace grpc_csharp_generator
 
index 5f13aa6..c503fd6 100644 (file)
@@ -39,6 +39,7 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     bool generate_client = true;
     bool generate_server = true;
     bool internal_access = false;
+    bool lite_client = false;
     for (size_t i = 0; i < options.size(); i++) {
       if (options[i].first == "no_client") {
         generate_client = false;
@@ -46,6 +47,10 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
         generate_server = false;
       } else if (options[i].first == "internal_access") {
         internal_access = true;
+      } else if (options[i].first == "lite_client") {
+        // will only be used if generate_client is true.
+        // NOTE: experimental option, can be removed in future release
+        lite_client = true;
       } else {
         *error = "Unknown generator option: " + options[i].first;
         return false;
@@ -53,7 +58,7 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     }
 
     grpc::string code = grpc_csharp_generator::GetServices(
-        file, generate_client, generate_server, internal_access);
+        file, generate_client, generate_server, internal_access, lite_client);
     if (code.size() == 0) {
       return true;  // don't generate a file if there are no services
     }
index dd76169..9e51a83 100644 (file)
@@ -65,8 +65,8 @@ GPR_GLOBAL_CONFIG_DEFINE_INT32(
     "idleness), so that the next RPC on this channel won't fail. Set to 0 to "
     "turn off the backup polls.");
 
-static void init_globals() {
-  gpr_mu_init(&g_poller_mu);
+void grpc_client_channel_global_init_backup_polling() {
+  gpr_once_init(&g_once, [] { gpr_mu_init(&g_poller_mu); });
   int32_t poll_interval_ms =
       GPR_GLOBAL_CONFIG_GET(grpc_client_channel_backup_poll_interval_ms);
   if (poll_interval_ms < 0) {
@@ -153,7 +153,6 @@ static void g_poller_init_locked() {
 
 void grpc_client_channel_start_backup_polling(
     grpc_pollset_set* interested_parties) {
-  gpr_once_init(&g_once, init_globals);
   if (g_poll_interval_ms == 0) {
     return;
   }
index e1bf4f8..b412081 100644 (file)
 
 GPR_GLOBAL_CONFIG_DECLARE_INT32(grpc_client_channel_backup_poll_interval_ms);
 
-/* Start polling \a interested_parties periodically in the timer thread  */
+/* Initializes backup polling. */
+void grpc_client_channel_global_init_backup_polling();
+
+/* Starts polling \a interested_parties periodically in the timer thread. */
 void grpc_client_channel_start_backup_polling(
     grpc_pollset_set* interested_parties);
 
-/* Stop polling \a interested_parties */
+/* Stops polling \a interested_parties. */
 void grpc_client_channel_stop_backup_polling(
     grpc_pollset_set* interested_parties);
 
index f774c98..0b612e6 100644 (file)
@@ -51,6 +51,7 @@
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/inlined_vector.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/map.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/iomgr.h"
@@ -66,7 +67,7 @@
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/status_metadata.h"
 
-using grpc_core::internal::ClientChannelMethodParsedObject;
+using grpc_core::internal::ClientChannelMethodParsedConfig;
 using grpc_core::internal::ServerRetryThrottleData;
 
 //
@@ -105,7 +106,6 @@ namespace {
 class ChannelData {
  public:
   struct QueuedPick {
-    LoadBalancingPolicy::PickArgs pick;
     grpc_call_element* elem;
     QueuedPick* next = nullptr;
   };
@@ -118,18 +118,6 @@ class ChannelData {
   static void GetChannelInfo(grpc_channel_element* elem,
                              const grpc_channel_info* info);
 
-  void set_channelz_node(channelz::ClientChannelNode* node) {
-    channelz_node_ = node;
-    resolving_lb_policy_->set_channelz_node(node->Ref());
-  }
-  void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                channelz::ChildRefsList* child_channels) {
-    if (resolving_lb_policy_ != nullptr) {
-      resolving_lb_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                     child_channels);
-    }
-  }
-
   bool deadline_checking_enabled() const { return deadline_checking_enabled_; }
   bool enable_retries() const { return enable_retries_; }
   size_t per_rpc_retry_buffer_size() const {
@@ -175,6 +163,7 @@ class ChannelData {
  private:
   class ConnectivityStateAndPickerSetter;
   class ServiceConfigSetter;
+  class GrpcSubchannel;
   class ClientChannelControlHelper;
 
   class ExternalConnectivityWatcher {
@@ -223,7 +212,7 @@ class ChannelData {
 
   static bool ProcessResolverResultLocked(
       void* arg, const Resolver::Result& result, const char** lb_policy_name,
-      RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
+      RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
       grpc_error** service_config_error);
 
   grpc_error* DoPingLocked(grpc_transport_op* op);
@@ -234,9 +223,9 @@ class ChannelData {
 
   void ProcessLbPolicy(
       const Resolver::Result& resolver_result,
-      const internal::ClientChannelGlobalParsedObject* parsed_service_config,
+      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
       UniquePtr<char>* lb_policy_name,
-      RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
+      RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config);
 
   //
   // Fields set at construction and never modified.
@@ -248,8 +237,7 @@ class ChannelData {
   ClientChannelFactory* client_channel_factory_;
   UniquePtr<char> server_name_;
   RefCountedPtr<ServiceConfig> default_service_config_;
-  // Initialized shortly after construction.
-  channelz::ClientChannelNode* channelz_node_ = nullptr;
+  channelz::ChannelNode* channelz_node_;
 
   //
   // Fields used in the data plane.  Guarded by data_plane_combiner.
@@ -268,12 +256,13 @@ class ChannelData {
   grpc_combiner* combiner_;
   grpc_pollset_set* interested_parties_;
   RefCountedPtr<SubchannelPoolInterface> subchannel_pool_;
-  OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy_;
+  OrphanablePtr<ResolvingLoadBalancingPolicy> resolving_lb_policy_;
   grpc_connectivity_state_tracker state_tracker_;
   ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
   UniquePtr<char> health_check_service_name_;
   RefCountedPtr<ServiceConfig> saved_service_config_;
   bool received_first_resolver_result_ = false;
+  Map<Subchannel*, int> subchannel_refcount_map_;
 
   //
   // Fields accessed from both data plane and control plane combiners.
@@ -315,6 +304,16 @@ class CallData {
  private:
   class QueuedPickCanceller;
 
+  class LbCallState : public LoadBalancingPolicy::CallState {
+   public:
+    explicit LbCallState(CallData* calld) : calld_(calld) {}
+
+    void* Alloc(size_t size) override { return calld_->arena_->Alloc(size); }
+
+   private:
+    CallData* calld_;
+  };
+
   // 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.
@@ -450,8 +449,9 @@ class CallData {
       grpc_call_element* elem, SubchannelCallBatchData* batch_data,
       SubchannelCallRetryState* retry_state);
 
-  static void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-      const LoadBalancingPolicy::PickArgs& pick,
+  static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
+      void* arg, grpc_error* error);
+  void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
       grpc_transport_stream_op_batch* batch);
 
   // Returns the index into pending_batches_ to be used for batch.
@@ -630,7 +630,7 @@ class CallData {
 
   RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
   ServiceConfig::CallData service_config_call_data_;
-  const ClientChannelMethodParsedObject* method_params_ = nullptr;
+  const ClientChannelMethodParsedConfig* method_params_ = nullptr;
 
   RefCountedPtr<SubchannelCall> subchannel_call_;
 
@@ -641,8 +641,19 @@ class CallData {
   bool pick_queued_ = false;
   bool service_config_applied_ = false;
   QueuedPickCanceller* pick_canceller_ = nullptr;
+  LbCallState lb_call_state_;
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+  void (*lb_recv_trailing_metadata_ready_)(
+      void* user_data, grpc_metadata_batch* recv_trailing_metadata,
+      LoadBalancingPolicy::CallState* call_state) = nullptr;
+  void* lb_recv_trailing_metadata_ready_user_data_ = nullptr;
   grpc_closure pick_closure_;
 
+  // For intercepting recv_trailing_metadata_ready for the LB policy.
+  grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
+  grpc_closure recv_trailing_metadata_ready_;
+  grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
+
   grpc_polling_entity* pollent_ = nullptr;
 
   // Batches are added to this list when received from above.
@@ -712,6 +723,7 @@ class ChannelData::ConnectivityStateAndPickerSetter {
     // Update connectivity state here, while holding control plane combiner.
     grpc_connectivity_state_set(&chand->state_tracker_, state, reason);
     if (chand->channelz_node_ != nullptr) {
+      chand->channelz_node_->SetConnectivityState(state);
       chand->channelz_node_->AddTraceEvent(
           channelz::ChannelTrace::Severity::Info,
           grpc_slice_from_static_string(
@@ -773,7 +785,7 @@ class ChannelData::ServiceConfigSetter {
  public:
   ServiceConfigSetter(
       ChannelData* chand,
-      Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
+      Optional<internal::ClientChannelGlobalParsedConfig::RetryThrottling>
           retry_throttle_data,
       RefCountedPtr<ServiceConfig> service_config)
       : chand_(chand),
@@ -812,7 +824,7 @@ class ChannelData::ServiceConfigSetter {
   }
 
   ChannelData* chand_;
-  Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
+  Optional<internal::ClientChannelGlobalParsedConfig::RetryThrottling>
       retry_throttle_data_;
   RefCountedPtr<ServiceConfig> service_config_;
   grpc_closure closure_;
@@ -935,6 +947,89 @@ void ChannelData::ExternalConnectivityWatcher::WatchConnectivityStateLocked(
 }
 
 //
+// ChannelData::GrpcSubchannel
+//
+
+// This class is a wrapper for Subchannel that hides details of the
+// channel's implementation (such as the health check service name) from
+// the LB policy API.
+//
+// Note that no synchronization is needed here, because even if the
+// underlying subchannel is shared between channels, this wrapper will only
+// be used within one channel, so it will always be synchronized by the
+// control plane combiner.
+class ChannelData::GrpcSubchannel : public SubchannelInterface {
+ public:
+  GrpcSubchannel(ChannelData* chand, Subchannel* subchannel,
+                 UniquePtr<char> health_check_service_name)
+      : chand_(chand),
+        subchannel_(subchannel),
+        health_check_service_name_(std::move(health_check_service_name)) {
+    GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "GrpcSubchannel");
+    auto* subchannel_node = subchannel_->channelz_node();
+    if (subchannel_node != nullptr) {
+      intptr_t subchannel_uuid = subchannel_node->uuid();
+      auto it = chand_->subchannel_refcount_map_.find(subchannel_);
+      if (it == chand_->subchannel_refcount_map_.end()) {
+        chand_->channelz_node_->AddChildSubchannel(subchannel_uuid);
+        it = chand_->subchannel_refcount_map_.emplace(subchannel_, 0).first;
+      }
+      ++it->second;
+    }
+  }
+
+  ~GrpcSubchannel() {
+    auto* subchannel_node = subchannel_->channelz_node();
+    if (subchannel_node != nullptr) {
+      intptr_t subchannel_uuid = subchannel_node->uuid();
+      auto it = chand_->subchannel_refcount_map_.find(subchannel_);
+      GPR_ASSERT(it != chand_->subchannel_refcount_map_.end());
+      --it->second;
+      if (it->second == 0) {
+        chand_->channelz_node_->RemoveChildSubchannel(subchannel_uuid);
+        chand_->subchannel_refcount_map_.erase(it);
+      }
+    }
+    GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB");
+    GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "GrpcSubchannel");
+  }
+
+  grpc_connectivity_state CheckConnectivityState(
+      RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
+      override {
+    RefCountedPtr<ConnectedSubchannel> tmp;
+    auto retval = subchannel_->CheckConnectivityState(
+        health_check_service_name_.get(), &tmp);
+    *connected_subchannel = std::move(tmp);
+    return retval;
+  }
+
+  void WatchConnectivityState(
+      grpc_connectivity_state initial_state,
+      UniquePtr<ConnectivityStateWatcher> watcher) override {
+    subchannel_->WatchConnectivityState(
+        initial_state,
+        UniquePtr<char>(gpr_strdup(health_check_service_name_.get())),
+        std::move(watcher));
+  }
+
+  void CancelConnectivityStateWatch(
+      ConnectivityStateWatcher* watcher) override {
+    subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(),
+                                              watcher);
+  }
+
+  void AttemptToConnect() override { subchannel_->AttemptToConnect(); }
+
+  void ResetBackoff() override { subchannel_->ResetBackoff(); }
+
+ private:
+  ChannelData* chand_;
+  Subchannel* subchannel_;
+  UniquePtr<char> health_check_service_name_;
+};
+
+//
 // ChannelData::ClientChannelControlHelper
 //
 
@@ -950,23 +1045,29 @@ class ChannelData::ClientChannelControlHelper
                              "ClientChannelControlHelper");
   }
 
-  Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
-    grpc_arg args_to_add[2];
-    int num_args_to_add = 0;
-    if (chand_->health_check_service_name_ != nullptr) {
-      args_to_add[0] = grpc_channel_arg_string_create(
-          const_cast<char*>("grpc.temp.health_check"),
-          const_cast<char*>(chand_->health_check_service_name_.get()));
-      num_args_to_add++;
+  RefCountedPtr<SubchannelInterface> CreateSubchannel(
+      const grpc_channel_args& args) override {
+    bool inhibit_health_checking = grpc_channel_arg_get_bool(
+        grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
+    UniquePtr<char> health_check_service_name;
+    if (!inhibit_health_checking) {
+      health_check_service_name.reset(
+          gpr_strdup(chand_->health_check_service_name_.get()));
     }
-    args_to_add[num_args_to_add++] = SubchannelPoolInterface::CreateChannelArg(
+    static const char* args_to_remove[] = {
+        GRPC_ARG_INHIBIT_HEALTH_CHECKING,
+        GRPC_ARG_CHANNELZ_CHANNEL_NODE,
+    };
+    grpc_arg arg = SubchannelPoolInterface::CreateChannelArg(
         chand_->subchannel_pool_.get());
-    grpc_channel_args* new_args =
-        grpc_channel_args_copy_and_add(&args, args_to_add, num_args_to_add);
+    grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
+        &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &arg, 1);
     Subchannel* subchannel =
         chand_->client_channel_factory_->CreateSubchannel(new_args);
     grpc_channel_args_destroy(new_args);
-    return subchannel;
+    if (subchannel == nullptr) return nullptr;
+    return MakeRefCounted<GrpcSubchannel>(chand_, subchannel,
+                                          std::move(health_check_service_name));
   }
 
   grpc_channel* CreateChannel(const char* target,
@@ -997,7 +1098,22 @@ class ChannelData::ClientChannelControlHelper
   // No-op -- we should never get this from ResolvingLoadBalancingPolicy.
   void RequestReresolution() override {}
 
+  void AddTraceEvent(TraceSeverity severity, const char* message) override {
+    if (chand_->channelz_node_ != nullptr) {
+      chand_->channelz_node_->AddTraceEvent(
+          ConvertSeverityEnum(severity),
+          grpc_slice_from_copied_string(message));
+    }
+  }
+
  private:
+  static channelz::ChannelTrace::Severity ConvertSeverityEnum(
+      TraceSeverity severity) {
+    if (severity == TRACE_INFO) return channelz::ChannelTrace::Info;
+    if (severity == TRACE_WARNING) return channelz::ChannelTrace::Warning;
+    return channelz::ChannelTrace::Error;
+  }
+
   ChannelData* chand_;
 };
 
@@ -1040,6 +1156,15 @@ RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
   return GlobalSubchannelPool::instance();
 }
 
+channelz::ChannelNode* GetChannelzNode(const grpc_channel_args* args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
+  if (arg != nullptr && arg->type == GRPC_ARG_POINTER) {
+    return static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
+  }
+  return nullptr;
+}
+
 ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
     : deadline_checking_enabled_(
           grpc_deadline_checking_enabled(args->channel_args)),
@@ -1049,11 +1174,16 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
       owning_stack_(args->channel_stack),
       client_channel_factory_(
           ClientChannelFactory::GetFromChannelArgs(args->channel_args)),
+      channelz_node_(GetChannelzNode(args->channel_args)),
       data_plane_combiner_(grpc_combiner_create()),
       combiner_(grpc_combiner_create()),
       interested_parties_(grpc_pollset_set_create()),
       subchannel_pool_(GetSubchannelPool(args->channel_args)),
       disconnect_error_(GRPC_ERROR_NONE) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+    gpr_log(GPR_INFO, "chand=%p: creating client_channel for channel stack %p",
+            this, owning_stack_);
+  }
   // Initialize data members.
   grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
                                "client_channel");
@@ -1078,8 +1208,6 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
   // Get default service config
   const char* service_config_json = grpc_channel_arg_get_string(
       grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG));
-  // TODO(yashkt): Make sure we set the channel in TRANSIENT_FAILURE on an
-  // invalid default service config
   if (service_config_json != nullptr) {
     *error = GRPC_ERROR_NONE;
     default_service_config_ = ServiceConfig::Create(service_config_json, error);
@@ -1135,6 +1263,9 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
 }
 
 ChannelData::~ChannelData() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+    gpr_log(GPR_INFO, "chand=%p: destroying channel", this);
+  }
   if (resolving_lb_policy_ != nullptr) {
     grpc_pollset_set_del_pollset_set(resolving_lb_policy_->interested_parties(),
                                      interested_parties_);
@@ -1152,9 +1283,9 @@ ChannelData::~ChannelData() {
 
 void ChannelData::ProcessLbPolicy(
     const Resolver::Result& resolver_result,
-    const internal::ClientChannelGlobalParsedObject* parsed_service_config,
+    const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
     UniquePtr<char>* lb_policy_name,
-    RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
+    RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
   // Prefer the LB policy name found in the service config.
   if (parsed_service_config != nullptr &&
       parsed_service_config->parsed_lb_config() != nullptr) {
@@ -1202,7 +1333,7 @@ void ChannelData::ProcessLbPolicy(
 // resolver result update.
 bool ChannelData::ProcessResolverResultLocked(
     void* arg, const Resolver::Result& result, const char** lb_policy_name,
-    RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
+    RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
     grpc_error** service_config_error) {
   ChannelData* chand = static_cast<ChannelData*>(arg);
   RefCountedPtr<ServiceConfig> service_config;
@@ -1247,16 +1378,17 @@ bool ChannelData::ProcessResolverResultLocked(
       result.service_config_error != GRPC_ERROR_NONE) {
     return false;
   }
-  UniquePtr<char> service_config_json;
   // Process service config.
-  const internal::ClientChannelGlobalParsedObject* parsed_service_config =
+  UniquePtr<char> service_config_json;
+  const internal::ClientChannelGlobalParsedConfig* parsed_service_config =
       nullptr;
   if (service_config != nullptr) {
     parsed_service_config =
-        static_cast<const internal::ClientChannelGlobalParsedObject*>(
-            service_config->GetParsedGlobalServiceConfigObject(
+        static_cast<const internal::ClientChannelGlobalParsedConfig*>(
+            service_config->GetGlobalParsedConfig(
                 internal::ClientChannelServiceConfigParser::ParserIndex()));
   }
+  // Check if the config has changed.
   const bool service_config_changed =
       ((service_config == nullptr) !=
        (chand->saved_service_config_ == nullptr)) ||
@@ -1272,20 +1404,22 @@ bool ChannelData::ProcessResolverResultLocked(
               "chand=%p: resolver returned updated service config: \"%s\"",
               chand, service_config_json.get());
     }
-    chand->saved_service_config_ = std::move(service_config);
-    if (parsed_service_config != nullptr) {
+    // Save health check service name.
+    if (service_config != nullptr) {
       chand->health_check_service_name_.reset(
           gpr_strdup(parsed_service_config->health_check_service_name()));
     } else {
       chand->health_check_service_name_.reset();
     }
+    // Save service config.
+    chand->saved_service_config_ = std::move(service_config);
   }
   // We want to set the service config at least once. This should not really be
   // needed, but we are doing it as a defensive approach. This can be removed,
   // if we feel it is unnecessary.
   if (service_config_changed || !chand->received_first_resolver_result_) {
     chand->received_first_resolver_result_ = true;
-    Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
+    Optional<internal::ClientChannelGlobalParsedConfig::RetryThrottling>
         retry_throttle_data;
     if (parsed_service_config != nullptr) {
       retry_throttle_data = parsed_service_config->retry_throttling();
@@ -1315,19 +1449,19 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
   if (grpc_connectivity_state_check(&state_tracker_) != GRPC_CHANNEL_READY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("channel not connected");
   }
-  LoadBalancingPolicy::PickArgs pick;
-  grpc_error* error = GRPC_ERROR_NONE;
-  picker_->Pick(&pick, &error);
-  if (pick.connected_subchannel != nullptr) {
-    pick.connected_subchannel->Ping(op->send_ping.on_initiate,
-                                    op->send_ping.on_ack);
+  LoadBalancingPolicy::PickResult result =
+      picker_->Pick(LoadBalancingPolicy::PickArgs());
+  if (result.connected_subchannel != nullptr) {
+    ConnectedSubchannel* connected_subchannel =
+        static_cast<ConnectedSubchannel*>(result.connected_subchannel.get());
+    connected_subchannel->Ping(op->send_ping.on_initiate, op->send_ping.on_ack);
   } else {
-    if (error == GRPC_ERROR_NONE) {
-      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    if (result.error == GRPC_ERROR_NONE) {
+      result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "LB policy dropped call on ping");
     }
   }
-  return error;
+  return result.error;
 }
 
 void ChannelData::StartTransportOpLocked(void* arg, grpc_error* ignored) {
@@ -1508,6 +1642,7 @@ CallData::CallData(grpc_call_element* elem, const ChannelData& chand,
       owning_call_(args.call_stack),
       call_combiner_(args.call_combiner),
       call_context_(args.context),
+      lb_call_state_(this),
       pending_send_initial_metadata_(false),
       pending_send_message_(false),
       pending_send_trailing_metadata_(false),
@@ -1740,18 +1875,30 @@ void CallData::FreeCachedSendOpDataForCompletedBatch(
 // LB recv_trailing_metadata_ready handling
 //
 
+void CallData::RecvTrailingMetadataReadyForLoadBalancingPolicy(
+    void* arg, grpc_error* error) {
+  CallData* calld = static_cast<CallData*>(arg);
+  // Invoke callback to LB policy.
+  calld->lb_recv_trailing_metadata_ready_(
+      calld->lb_recv_trailing_metadata_ready_user_data_,
+      calld->recv_trailing_metadata_, &calld->lb_call_state_);
+  // Chain to original callback.
+  GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready_,
+                   GRPC_ERROR_REF(error));
+}
+
 void CallData::MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-    const LoadBalancingPolicy::PickArgs& pick,
     grpc_transport_stream_op_batch* batch) {
-  if (pick.recv_trailing_metadata_ready != nullptr) {
-    *pick.original_recv_trailing_metadata_ready =
+  if (lb_recv_trailing_metadata_ready_ != nullptr) {
+    recv_trailing_metadata_ =
+        batch->payload->recv_trailing_metadata.recv_trailing_metadata;
+    original_recv_trailing_metadata_ready_ =
         batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+    GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
+                      RecvTrailingMetadataReadyForLoadBalancingPolicy, this,
+                      grpc_schedule_on_exec_ctx);
     batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
-        pick.recv_trailing_metadata_ready;
-    if (pick.recv_trailing_metadata != nullptr) {
-      *pick.recv_trailing_metadata =
-          batch->payload->recv_trailing_metadata.recv_trailing_metadata;
-    }
+        &recv_trailing_metadata_ready_;
   }
 }
 
@@ -1897,8 +2044,7 @@ void CallData::PendingBatchesFail(
     grpc_transport_stream_op_batch* batch = pending->batch;
     if (batch != nullptr) {
       if (batch->recv_trailing_metadata) {
-        MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
-                                                                   batch);
+        MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
       }
       batch->handler_private.extra_arg = this;
       GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@@ -1952,8 +2098,7 @@ void CallData::PendingBatchesResume(grpc_call_element* elem) {
     grpc_transport_stream_op_batch* batch = pending->batch;
     if (batch != nullptr) {
       if (batch->recv_trailing_metadata) {
-        MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
-                                                                   batch);
+        MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
       }
       batch->handler_private.extra_arg = subchannel_call_.get();
       GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@@ -2014,7 +2159,7 @@ void CallData::DoRetry(grpc_call_element* elem,
   GPR_ASSERT(retry_policy != nullptr);
   // Reset subchannel call and connected subchannel.
   subchannel_call_.reset();
-  pick_.pick.connected_subchannel.reset();
+  connected_subchannel_.reset();
   // Compute backoff delay.
   grpc_millis next_attempt_time;
   if (server_pushback_ms >= 0) {
@@ -2871,7 +3016,7 @@ void CallData::AddRetriableRecvTrailingMetadataOp(
       .recv_trailing_metadata_ready =
       &retry_state->recv_trailing_metadata_ready;
   MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-      pick_.pick, &batch_data->batch);
+      &batch_data->batch);
 }
 
 void CallData::StartInternalRecvTrailingMetadata(grpc_call_element* elem) {
@@ -3138,8 +3283,7 @@ void CallData::CreateSubchannelCall(grpc_call_element* elem) {
       // need to use a separate call context for each subchannel call.
       call_context_, call_combiner_, parent_data_size};
   grpc_error* error = GRPC_ERROR_NONE;
-  subchannel_call_ =
-      pick_.pick.connected_subchannel->CreateCall(call_args, &error);
+  subchannel_call_ = connected_subchannel_->CreateCall(call_args, &error);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
             chand, this, subchannel_call_.get(), grpc_error_string(error));
@@ -3248,10 +3392,10 @@ void CallData::ApplyServiceConfigToCallLocked(grpc_call_element* elem) {
   service_config_call_data_ =
       ServiceConfig::CallData(chand->service_config(), path_);
   if (service_config_call_data_.service_config() != nullptr) {
-    call_context_[GRPC_SERVICE_CONFIG_CALL_DATA].value =
+    call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value =
         &service_config_call_data_;
-    method_params_ = static_cast<ClientChannelMethodParsedObject*>(
-        service_config_call_data_.GetMethodParsedObject(
+    method_params_ = static_cast<ClientChannelMethodParsedConfig*>(
+        service_config_call_data_.GetMethodParsedConfig(
             internal::ClientChannelServiceConfigParser::ParserIndex()));
   }
   retry_throttle_data_ = chand->retry_throttle_data();
@@ -3300,13 +3444,14 @@ void CallData::MaybeApplyServiceConfigToCallLocked(grpc_call_element* elem) {
   }
 }
 
-const char* PickResultName(LoadBalancingPolicy::PickResult result) {
-  switch (result) {
-    case LoadBalancingPolicy::PICK_COMPLETE:
+const char* PickResultTypeName(
+    LoadBalancingPolicy::PickResult::ResultType type) {
+  switch (type) {
+    case LoadBalancingPolicy::PickResult::PICK_COMPLETE:
       return "COMPLETE";
-    case LoadBalancingPolicy::PICK_QUEUE:
+    case LoadBalancingPolicy::PickResult::PICK_QUEUE:
       return "QUEUE";
-    case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE:
+    case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE:
       return "TRANSIENT_FAILURE";
   }
   GPR_UNREACHABLE_CODE(return "UNKNOWN");
@@ -3316,8 +3461,10 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
-  GPR_ASSERT(calld->pick_.pick.connected_subchannel == nullptr);
+  GPR_ASSERT(calld->connected_subchannel_ == nullptr);
   GPR_ASSERT(calld->subchannel_call_ == nullptr);
+  // Apply service config to call if needed.
+  calld->MaybeApplyServiceConfigToCallLocked(elem);
   // If this is a retry, use the send_initial_metadata payload that
   // we've cached; otherwise, use the pending batch.  The
   // send_initial_metadata batch will be the first pending batch in the
@@ -3328,58 +3475,58 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
   // allocate the subchannel batch earlier so that we can give the
   // subchannel's copy of the metadata batch (which is copied for each
   // attempt) to the LB policy instead the one from the parent channel.
-  calld->pick_.pick.initial_metadata =
+  LoadBalancingPolicy::PickArgs pick_args;
+  pick_args.call_state = &calld->lb_call_state_;
+  pick_args.initial_metadata =
       calld->seen_send_initial_metadata_
           ? &calld->send_initial_metadata_
           : calld->pending_batches_[0]
                 .batch->payload->send_initial_metadata.send_initial_metadata;
-  uint32_t* send_initial_metadata_flags =
+  // Grab initial metadata flags so that we can check later if the call has
+  // wait_for_ready enabled.
+  const uint32_t send_initial_metadata_flags =
       calld->seen_send_initial_metadata_
-          ? &calld->send_initial_metadata_flags_
-          : &calld->pending_batches_[0]
-                 .batch->payload->send_initial_metadata
-                 .send_initial_metadata_flags;
-  // Apply service config to call if needed.
-  calld->MaybeApplyServiceConfigToCallLocked(elem);
+          ? calld->send_initial_metadata_flags_
+          : calld->pending_batches_[0]
+                .batch->payload->send_initial_metadata
+                .send_initial_metadata_flags;
   // When done, we schedule this closure to leave the data plane combiner.
   GRPC_CLOSURE_INIT(&calld->pick_closure_, PickDone, elem,
                     grpc_schedule_on_exec_ctx);
   // Attempt pick.
-  error = GRPC_ERROR_NONE;
-  auto pick_result = chand->picker()->Pick(&calld->pick_.pick, &error);
+  auto result = chand->picker()->Pick(pick_args);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO,
             "chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, "
             "error=%s)",
-            chand, calld, PickResultName(pick_result),
-            calld->pick_.pick.connected_subchannel.get(),
-            grpc_error_string(error));
+            chand, calld, PickResultTypeName(result.type),
+            result.connected_subchannel.get(), grpc_error_string(result.error));
   }
-  switch (pick_result) {
-    case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: {
+  switch (result.type) {
+    case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: {
       // If we're shutting down, fail all RPCs.
       grpc_error* disconnect_error = chand->disconnect_error();
       if (disconnect_error != GRPC_ERROR_NONE) {
-        GRPC_ERROR_UNREF(error);
+        GRPC_ERROR_UNREF(result.error);
         GRPC_CLOSURE_SCHED(&calld->pick_closure_,
                            GRPC_ERROR_REF(disconnect_error));
         break;
       }
       // If wait_for_ready is false, then the error indicates the RPC
       // attempt's final status.
-      if ((*send_initial_metadata_flags &
+      if ((send_initial_metadata_flags &
            GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
         // Retry if appropriate; otherwise, fail.
         grpc_status_code status = GRPC_STATUS_OK;
-        grpc_error_get_status(error, calld->deadline_, &status, nullptr,
+        grpc_error_get_status(result.error, calld->deadline_, &status, nullptr,
                               nullptr, nullptr);
         if (!calld->enable_retries_ ||
             !calld->MaybeRetry(elem, nullptr /* batch_data */, status,
                                nullptr /* server_pushback_md */)) {
           grpc_error* new_error =
               GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                  "Failed to pick subchannel", &error, 1);
-          GRPC_ERROR_UNREF(error);
+                  "Failed to pick subchannel", &result.error, 1);
+          GRPC_ERROR_UNREF(result.error);
           GRPC_CLOSURE_SCHED(&calld->pick_closure_, new_error);
         }
         if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
@@ -3387,19 +3534,24 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
       }
       // If wait_for_ready is true, then queue to retry when we get a new
       // picker.
-      GRPC_ERROR_UNREF(error);
+      GRPC_ERROR_UNREF(result.error);
     }
     // Fallthrough
-    case LoadBalancingPolicy::PICK_QUEUE:
+    case LoadBalancingPolicy::PickResult::PICK_QUEUE:
       if (!calld->pick_queued_) calld->AddCallToQueuedPicksLocked(elem);
       break;
     default:  // PICK_COMPLETE
       // Handle drops.
-      if (GPR_UNLIKELY(calld->pick_.pick.connected_subchannel == nullptr)) {
-        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+      if (GPR_UNLIKELY(result.connected_subchannel == nullptr)) {
+        result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             "Call dropped by load balancing policy");
       }
-      GRPC_CLOSURE_SCHED(&calld->pick_closure_, error);
+      calld->connected_subchannel_ = std::move(result.connected_subchannel);
+      calld->lb_recv_trailing_metadata_ready_ =
+          result.recv_trailing_metadata_ready;
+      calld->lb_recv_trailing_metadata_ready_user_data_ =
+          result.recv_trailing_metadata_ready_user_data;
+      GRPC_CLOSURE_SCHED(&calld->pick_closure_, result.error);
       if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
   }
 }
@@ -3428,20 +3580,6 @@ const grpc_channel_filter grpc_client_channel_filter = {
     "client-channel",
 };
 
-void grpc_client_channel_set_channelz_node(
-    grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->set_channelz_node(node);
-}
-
-void grpc_client_channel_populate_child_refs(
-    grpc_channel_element* elem,
-    grpc_core::channelz::ChildRefsList* child_subchannels,
-    grpc_core::channelz::ChildRefsList* child_channels) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->FillChildRefsForChannelz(child_subchannels, child_channels);
-}
-
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_channel_element* elem, int try_to_connect) {
   auto* chand = static_cast<ChannelData*>(elem->channel_data);
index 5bfff4d..caaa079 100644 (file)
@@ -40,14 +40,6 @@ extern grpc_core::TraceFlag grpc_client_channel_trace;
 
 extern const grpc_channel_filter grpc_client_channel_filter;
 
-void grpc_client_channel_set_channelz_node(
-    grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node);
-
-void grpc_client_channel_populate_child_refs(
-    grpc_channel_element* elem,
-    grpc_core::channelz::ChildRefsList* child_subchannels,
-    grpc_core::channelz::ChildRefsList* child_channels);
-
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_channel_element* elem, int try_to_connect);
 
index a7a47e9..e068d11 100644 (file)
 
 namespace grpc_core {
 namespace channelz {
-namespace {
-
-void* client_channel_channelz_copy(void* p) { return p; }
-
-void client_channel_channelz_destroy(void* p) {}
-
-int client_channel_channelz_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-
-}  // namespace
-
-static const grpc_arg_pointer_vtable client_channel_channelz_vtable = {
-    client_channel_channelz_copy, client_channel_channelz_destroy,
-    client_channel_channelz_cmp};
-
-ClientChannelNode::ClientChannelNode(grpc_channel* channel,
-                                     size_t channel_tracer_max_nodes,
-                                     bool is_top_level_channel)
-    : ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) {
-  client_channel_ =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter);
-  grpc_client_channel_set_channelz_node(client_channel_, this);
-}
-
-void ClientChannelNode::PopulateConnectivityState(grpc_json* json) {
-  grpc_connectivity_state state;
-  if (ChannelIsDestroyed()) {
-    state = GRPC_CHANNEL_SHUTDOWN;
-  } else {
-    state =
-        grpc_client_channel_check_connectivity_state(client_channel_, false);
-  }
-  json = grpc_json_create_child(nullptr, json, "state", nullptr,
-                                GRPC_JSON_OBJECT, false);
-  grpc_json_create_child(nullptr, json, "state",
-                         grpc_connectivity_state_name(state), GRPC_JSON_STRING,
-                         false);
-}
-
-void ClientChannelNode::PopulateChildRefs(grpc_json* json) {
-  ChildRefsList child_subchannels;
-  ChildRefsList child_channels;
-  grpc_json* json_iterator = nullptr;
-  grpc_client_channel_populate_child_refs(client_channel_, &child_subchannels,
-                                          &child_channels);
-  if (!child_subchannels.empty()) {
-    grpc_json* array_parent = grpc_json_create_child(
-        nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false);
-    for (size_t i = 0; i < child_subchannels.size(); ++i) {
-      json_iterator =
-          grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
-                                 GRPC_JSON_OBJECT, false);
-      grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId",
-                                        child_subchannels[i]);
-    }
-  }
-  if (!child_channels.empty()) {
-    grpc_json* array_parent = grpc_json_create_child(
-        nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false);
-    json_iterator = nullptr;
-    for (size_t i = 0; i < child_channels.size(); ++i) {
-      json_iterator =
-          grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
-                                 GRPC_JSON_OBJECT, false);
-      grpc_json_add_number_string_child(json_iterator, nullptr, "channelId",
-                                        child_channels[i]);
-    }
-  }
-}
-
-grpc_arg ClientChannelNode::CreateChannelArg() {
-  return grpc_channel_arg_pointer_create(
-      const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC),
-      reinterpret_cast<void*>(MakeClientChannelNode),
-      &client_channel_channelz_vtable);
-}
-
-RefCountedPtr<ChannelNode> ClientChannelNode::MakeClientChannelNode(
-    grpc_channel* channel, size_t channel_tracer_max_nodes,
-    bool is_top_level_channel) {
-  return MakeRefCounted<ClientChannelNode>(channel, channel_tracer_max_nodes,
-                                           is_top_level_channel);
-}
 
 SubchannelNode::SubchannelNode(Subchannel* subchannel,
                                size_t channel_tracer_max_nodes)
@@ -127,7 +44,9 @@ void SubchannelNode::PopulateConnectivityState(grpc_json* json) {
   if (subchannel_ == nullptr) {
     state = GRPC_CHANNEL_SHUTDOWN;
   } else {
-    state = subchannel_->CheckConnectivity(true /* inhibit_health_checking */);
+    state = subchannel_->CheckConnectivityState(
+        nullptr /* health_check_service_name */,
+        nullptr /* connected_subchannel */);
   }
   json = grpc_json_create_child(nullptr, json, "state", nullptr,
                                 GRPC_JSON_OBJECT, false);
index 9272116..9f11e92 100644 (file)
@@ -32,32 +32,6 @@ class Subchannel;
 
 namespace channelz {
 
-// Subtype of ChannelNode that overrides and provides client_channel specific
-// functionality like querying for connectivity_state and subchannel data.
-class ClientChannelNode : public ChannelNode {
- public:
-  static RefCountedPtr<ChannelNode> MakeClientChannelNode(
-      grpc_channel* channel, size_t channel_tracer_max_nodes,
-      bool is_top_level_channel);
-
-  ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
-                    bool is_top_level_channel);
-  virtual ~ClientChannelNode() {}
-
-  // Overriding template methods from ChannelNode to render information that
-  // only ClientChannelNode knows about.
-  void PopulateConnectivityState(grpc_json* json) override;
-  void PopulateChildRefs(grpc_json* json) override;
-
-  // Helper to create a channel arg to ensure this type of ChannelNode is
-  // created.
-  static grpc_arg CreateChannelArg();
-
- private:
-  grpc_channel_element* client_channel_;
-};
-
-// Handles channelz bookkeeping for sockets
 class SubchannelNode : public BaseNode {
  public:
   SubchannelNode(Subchannel* subchannel, size_t channel_tracer_max_nodes);
@@ -85,12 +59,12 @@ class SubchannelNode : public BaseNode {
   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
 
  private:
+  void PopulateConnectivityState(grpc_json* json);
+
   Subchannel* subchannel_;
   UniquePtr<char> target_;
   CallCountingHelper call_counter_;
   ChannelTrace trace_;
-
-  void PopulateConnectivityState(grpc_json* json);
 };
 
 }  // namespace channelz
index e564df8..c5662e2 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <grpc/support/alloc.h>
 
+#include "src/core/ext/filters/client_channel/backup_poller.h"
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/client_channel_channelz.h"
 #include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
 #include "src/core/lib/surface/channel_init.h"
 
 static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
-  const grpc_channel_args* args =
-      grpc_channel_stack_builder_get_channel_arguments(builder);
-  grpc_arg args_to_add[] = {
-      grpc_core::channelz::ClientChannelNode::CreateChannelArg()};
-  grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
-      args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
-  grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
-  grpc_channel_args_destroy(new_args);
   return grpc_channel_stack_builder_append_filter(
       builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
 }
@@ -62,6 +55,7 @@ void grpc_client_channel_init(void) {
       GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
       (void*)&grpc_client_channel_filter);
   grpc_http_connect_register_handshaker_factory();
+  grpc_client_channel_global_init_backup_polling();
 }
 
 void grpc_client_channel_shutdown(void) {
index bfac773..faa2ba5 100644 (file)
@@ -323,6 +323,11 @@ void HealthCheckClient::CallState::StartCall() {
   grpc_error* error = GRPC_ERROR_NONE;
   call_ = health_check_client_->connected_subchannel_->CreateCall(args, &error)
               .release();
+  // Register after-destruction callback.
+  GRPC_CLOSURE_INIT(&after_call_stack_destruction_, AfterCallStackDestruction,
+                    this, grpc_schedule_on_exec_ctx);
+  call_->SetAfterCallStackDestroy(&after_call_stack_destruction_);
+  // Check if creation failed.
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "HealthCheckClient %p CallState %p: error creating health "
@@ -338,10 +343,6 @@ void HealthCheckClient::CallState::StartCall() {
         GRPC_ERROR_NONE);
     return;
   }
-  // Register after-destruction callback.
-  GRPC_CLOSURE_INIT(&after_call_stack_destruction_, AfterCallStackDestruction,
-                    this, grpc_schedule_on_exec_ctx);
-  call_->SetAfterCallStackDestroy(&after_call_stack_destruction_);
   // Initialize payload and batch.
   payload_.context = context_;
   batch_.payload = &payload_;
index 6fa7993..3e4d370 100644 (file)
@@ -105,7 +105,7 @@ LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
 //
 
 LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
-    PickArgs* pick, grpc_error** error) {
+    PickArgs args) {
   // We invoke the parent's ExitIdleLocked() via a closure instead
   // of doing it directly here, for two reasons:
   // 1. ExitIdleLocked() may cause the policy's state to change and
@@ -125,7 +125,9 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
                             grpc_combiner_scheduler(parent_->combiner())),
         GRPC_ERROR_NONE);
   }
-  return PICK_QUEUE;
+  PickResult result;
+  result.type = PickResult::PICK_QUEUE;
+  return result;
 }
 
 void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
@@ -135,4 +137,16 @@ void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
   parent->Unref();
 }
 
+//
+// LoadBalancingPolicy::TransientFailurePicker
+//
+
+LoadBalancingPolicy::PickResult
+LoadBalancingPolicy::TransientFailurePicker::Pick(PickArgs args) {
+  PickResult result;
+  result.type = PickResult::PICK_TRANSIENT_FAILURE;
+  result.error = GRPC_ERROR_REF(error_);
+  return result;
+}
+
 }  // namespace grpc_core
index 2ac7df6..f98a41d 100644 (file)
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
-#include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel_interface.h"
 #include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/transport/connectivity_state.h"
-
-extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
+#include "src/core/lib/transport/metadata_batch.h"
 
 namespace grpc_core {
 
-/// Interface for parsed forms of load balancing configs found in a service
-/// config.
-class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
- public:
-  virtual ~ParsedLoadBalancingConfig() = default;
-
-  // Returns the load balancing policy name
-  virtual const char* name() const GRPC_ABSTRACT;
-
-  GRPC_ABSTRACT_BASE_CLASS;
-};
+extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
 
 /// Interface for load balancing policies.
 ///
@@ -89,66 +77,77 @@ class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
 // interested_parties() hooks from the API.
 class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
  public:
+  /// Interface for accessing per-call state.
+  class CallState {
+   public:
+    CallState() = default;
+    virtual ~CallState() = default;
+
+    /// Allocates memory associated with the call, which will be
+    /// automatically freed when the call is complete.
+    /// It is more efficient to use this than to allocate memory directly
+    /// for allocations that need to be made on a per-call basis.
+    virtual void* Alloc(size_t size) GRPC_ABSTRACT;
+
+    GRPC_ABSTRACT_BASE_CLASS
+  };
+
   /// Arguments used when picking a subchannel for an RPC.
   struct PickArgs {
-    ///
-    /// Input parameters.
-    ///
     /// Initial metadata associated with the picking call.
     /// The LB policy may use the existing metadata to influence its routing
     /// decision, and it may add new metadata elements to be sent with the
     /// call to the chosen backend.
     // TODO(roth): Provide a more generic metadata API here.
     grpc_metadata_batch* initial_metadata = nullptr;
-    /// Storage for LB token in \a initial_metadata, or nullptr if not used.
-    // TODO(roth): Remove this from the API.  Maybe have the LB policy
-    // allocate this on the arena instead?
-    grpc_linked_mdelem lb_token_mdelem_storage;
-    ///
-    /// Output parameters.
-    ///
-    /// 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;
-    /// Callback set by lb policy to be notified of trailing metadata.
-    /// The callback must be scheduled on grpc_schedule_on_exec_ctx.
-    // TODO(roth): Provide a cleaner callback API.
-    grpc_closure* recv_trailing_metadata_ready = nullptr;
-    /// The address that will be set to point to the original
-    /// recv_trailing_metadata_ready callback, to be invoked by the LB
-    /// policy's recv_trailing_metadata_ready callback when complete.
-    /// Must be non-null if recv_trailing_metadata_ready is non-null.
-    // TODO(roth): Consider making the recv_trailing_metadata closure a
-    // synchronous callback, in which case it is not responsible for
-    // chaining to the next callback, so this can be removed from the API.
-    grpc_closure** original_recv_trailing_metadata_ready = nullptr;
-    /// If this is not nullptr, then the client channel will point it to the
-    /// call's trailing metadata before invoking recv_trailing_metadata_ready.
-    /// If this is nullptr, then the callback will still be called.
-    /// The lb does not have ownership of the metadata.
-    // TODO(roth): If we make this a synchronous callback, then this can
-    // be passed to the callback as a parameter and can be removed from
-    // the API here.
-    grpc_metadata_batch** recv_trailing_metadata = nullptr;
+    /// An interface for accessing call state.  Can be used to allocate
+    /// data associated with the call in an efficient way.
+    CallState* call_state;
   };
 
   /// The result of picking a subchannel for an RPC.
-  enum PickResult {
-    // Pick complete.  If connected_subchannel is non-null, client channel
-    // can immediately proceed with the call on connected_subchannel;
-    // otherwise, call should be dropped.
-    PICK_COMPLETE,
-    // Pick cannot be completed until something changes on the control
-    // plane.  Client channel will queue the pick and try again the
-    // next time the picker is updated.
-    PICK_QUEUE,
-    // LB policy is in transient failure.  If the pick is wait_for_ready,
-    // client channel will wait for the next picker and try again;
-    // otherwise, the call will be failed immediately (although it may
-    // be retried if the client channel is configured to do so).
-    // The Pick() method will set its error parameter if this value is
-    // returned.
-    PICK_TRANSIENT_FAILURE,
+  struct PickResult {
+    enum ResultType {
+      /// Pick complete.  If connected_subchannel is non-null, client channel
+      /// can immediately proceed with the call on connected_subchannel;
+      /// otherwise, call should be dropped.
+      PICK_COMPLETE,
+      /// Pick cannot be completed until something changes on the control
+      /// plane.  Client channel will queue the pick and try again the
+      /// next time the picker is updated.
+      PICK_QUEUE,
+      /// LB policy is in transient failure.  If the pick is wait_for_ready,
+      /// client channel will wait for the next picker and try again;
+      /// otherwise, the call will be failed immediately (although it may
+      /// be retried if the client channel is configured to do so).
+      /// The Pick() method will set its error parameter if this value is
+      /// returned.
+      PICK_TRANSIENT_FAILURE,
+    };
+    ResultType type;
+
+    /// Used only if type is PICK_COMPLETE.  Will be set to the selected
+    /// subchannel, or nullptr if the LB policy decides to drop the call.
+    RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel;
+
+    /// Used only if type is PICK_TRANSIENT_FAILURE.
+    /// Error to be set when returning a transient failure.
+    // TODO(roth): Replace this with something similar to grpc::Status,
+    // so that we don't expose grpc_error to this API.
+    grpc_error* error = GRPC_ERROR_NONE;
+
+    /// Used only if type is PICK_COMPLETE.
+    /// Callback set by lb policy to be notified of trailing metadata.
+    /// The user_data argument will be set to the
+    /// recv_trailing_metadata_ready_user_data field.
+    /// recv_trailing_metadata will be set to the metadata, which may be
+    /// modified by the callback.  The callback does not take ownership,
+    /// however, so any data that needs to be used after returning must
+    /// be copied.
+    void (*recv_trailing_metadata_ready)(
+        void* user_data, grpc_metadata_batch* recv_trailing_metadata,
+        CallState* call_state) = nullptr;
+    void* recv_trailing_metadata_ready_user_data = nullptr;
   };
 
   /// A subchannel picker is the object used to pick the subchannel to
@@ -162,17 +161,14 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
   /// live in the LB policy object itself.
   ///
   /// Currently, pickers are always accessed from within the
-  /// client_channel combiner, so they do not have to be thread-safe.
-  // TODO(roth): In a subsequent PR, split the data plane work (i.e.,
-  // the interaction with the picker) and the control plane work (i.e.,
-  // the interaction with the LB policy) into two different
-  // synchronization mechanisms, to avoid lock contention between the two.
+  /// client_channel data plane combiner, so they do not have to be
+  /// thread-safe.
   class SubchannelPicker {
    public:
     SubchannelPicker() = default;
     virtual ~SubchannelPicker() = default;
 
-    virtual PickResult Pick(PickArgs* pick, grpc_error** error) GRPC_ABSTRACT;
+    virtual PickResult Pick(PickArgs args) GRPC_ABSTRACT;
 
     GRPC_ABSTRACT_BASE_CLASS
   };
@@ -188,8 +184,8 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     virtual ~ChannelControlHelper() = default;
 
     /// Creates a new subchannel with the specified channel args.
-    virtual Subchannel* CreateSubchannel(const grpc_channel_args& args)
-        GRPC_ABSTRACT;
+    virtual RefCountedPtr<SubchannelInterface> CreateSubchannel(
+        const grpc_channel_args& args) GRPC_ABSTRACT;
 
     /// Creates a channel with the specified target and channel args.
     /// This can be used in cases where the LB policy needs to create a
@@ -205,6 +201,25 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     /// Requests that the resolver re-resolve.
     virtual void RequestReresolution() GRPC_ABSTRACT;
 
+    /// Adds a trace message associated with the channel.
+    /// Does NOT take ownership of \a message.
+    enum TraceSeverity { TRACE_INFO, TRACE_WARNING, TRACE_ERROR };
+    virtual void AddTraceEvent(TraceSeverity severity,
+                               const char* message) GRPC_ABSTRACT;
+
+    GRPC_ABSTRACT_BASE_CLASS
+  };
+
+  /// Interface for configuration data used by an LB policy implementation.
+  /// Individual implementations will create a subclass that adds methods to
+  /// return the parameters they need.
+  class Config : public RefCounted<Config> {
+   public:
+    virtual ~Config() = default;
+
+    // Returns the load balancing policy name
+    virtual const char* name() const GRPC_ABSTRACT;
+
     GRPC_ABSTRACT_BASE_CLASS
   };
 
@@ -212,7 +227,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
   /// config are available.
   struct UpdateArgs {
     ServerAddressList addresses;
-    RefCountedPtr<ParsedLoadBalancingConfig> config;
+    RefCountedPtr<Config> config;
     const grpc_channel_args* args = nullptr;
 
     // TODO(roth): Remove everything below once channel args is
@@ -265,20 +280,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
   /// Resets connection backoff.
   virtual void ResetBackoffLocked() GRPC_ABSTRACT;
 
-  /// Populates child_subchannels and child_channels with the uuids of this
-  /// LB policy's referenced children.
-  ///
-  /// This is not invoked from the client_channel's combiner. The
-  /// implementation is responsible for providing its own synchronization.
-  virtual void FillChildRefsForChannelz(
-      channelz::ChildRefsList* child_subchannels,
-      channelz::ChildRefsList* child_channels) GRPC_ABSTRACT;
-
-  void set_channelz_node(
-      RefCountedPtr<channelz::ClientChannelNode> channelz_node) {
-    channelz_node_ = std::move(channelz_node);
-  }
-
   grpc_pollset_set* interested_parties() const { return interested_parties_; }
 
   void Orphan() override;
@@ -291,7 +292,9 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     explicit QueuePicker(RefCountedPtr<LoadBalancingPolicy> parent)
         : parent_(std::move(parent)) {}
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override;
+    ~QueuePicker() { parent_.reset(DEBUG_LOCATION, "QueuePicker"); }
+
+    PickResult Pick(PickArgs args) override;
 
    private:
     static void CallExitIdle(void* arg, grpc_error* error);
@@ -306,10 +309,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     explicit TransientFailurePicker(grpc_error* error) : error_(error) {}
     ~TransientFailurePicker() override { GRPC_ERROR_UNREF(error_); }
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override {
-      *error = GRPC_ERROR_REF(error_);
-      return PICK_TRANSIENT_FAILURE;
-    }
+    PickResult Pick(PickArgs args) override;
 
    private:
     grpc_error* error_;
@@ -327,10 +327,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     return channel_control_helper_.get();
   }
 
-  channelz::ClientChannelNode* channelz_node() const {
-    return channelz_node_.get();
-  }
-
   /// Shuts down the policy.
   virtual void ShutdownLocked() GRPC_ABSTRACT;
 
@@ -343,8 +339,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
   grpc_pollset_set* interested_parties_;
   /// Channel control helper.
   UniquePtr<ChannelControlHelper> channel_control_helper_;
-  /// Channelz node.
-  RefCountedPtr<channelz::ClientChannelNode> channelz_node_;
 };
 
 }  // namespace grpc_core
index ed6e8de..a87dfda 100644 (file)
@@ -118,19 +118,19 @@ namespace {
 
 constexpr char kGrpclb[] = "grpclb";
 
-class ParsedGrpcLbConfig : public ParsedLoadBalancingConfig {
+class ParsedGrpcLbConfig : public LoadBalancingPolicy::Config {
  public:
   explicit ParsedGrpcLbConfig(
-      RefCountedPtr<ParsedLoadBalancingConfig> child_policy)
+      RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
       : child_policy_(std::move(child_policy)) {}
   const char* name() const override { return kGrpclb; }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
     return child_policy_;
   }
 
  private:
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
 };
 
 class GrpcLb : public LoadBalancingPolicy {
@@ -141,9 +141,6 @@ class GrpcLb : public LoadBalancingPolicy {
 
   void UpdateLocked(UpdateArgs args) override;
   void ResetBackoffLocked() override;
-  void FillChildRefsForChannelz(
-      channelz::ChildRefsList* child_subchannels,
-      channelz::ChildRefsList* child_channels) override;
 
  private:
   /// Contains a call to the LB server and all the data related to the call.
@@ -274,7 +271,7 @@ class GrpcLb : public LoadBalancingPolicy {
           child_picker_(std::move(child_picker)),
           client_stats_(std::move(client_stats)) {}
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override;
+    PickResult Pick(PickArgs args) override;
 
    private:
     // Storing the address for logging, but not holding a ref.
@@ -293,12 +290,14 @@ class GrpcLb : public LoadBalancingPolicy {
     explicit Helper(RefCountedPtr<GrpcLb> parent)
         : parent_(std::move(parent)) {}
 
-    Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
+    RefCountedPtr<SubchannelInterface> CreateSubchannel(
+        const grpc_channel_args& args) override;
     grpc_channel* CreateChannel(const char* target,
                                 const grpc_channel_args& args) override;
     void UpdateState(grpc_connectivity_state state,
                      UniquePtr<SubchannelPicker> picker) override;
     void RequestReresolution() override;
+    void AddTraceEvent(TraceSeverity severity, const char* message) override;
 
     void set_child(LoadBalancingPolicy* child) { child_ = child; }
 
@@ -348,8 +347,6 @@ class GrpcLb : public LoadBalancingPolicy {
 
   // The channel for communicating with the LB server.
   grpc_channel* lb_channel_ = nullptr;
-  // Uuid of the lb channel. Used for channelz.
-  gpr_atm lb_channel_uuid_ = 0;
   // Response generator to inject address updates into lb_channel_.
   RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
 
@@ -385,16 +382,13 @@ class GrpcLb : public LoadBalancingPolicy {
   grpc_connectivity_state lb_channel_connectivity_ = GRPC_CHANNEL_IDLE;
   grpc_closure lb_channel_on_connectivity_changed_;
 
-  // Lock held when modifying the value of child_policy_ or
-  // pending_child_policy_.
-  gpr_mu child_policy_mu_;
   // The child policy to use for the backends.
   OrphanablePtr<LoadBalancingPolicy> child_policy_;
   // When switching child policies, the new policy will be stored here
   // until it reports READY, at which point it will be moved to child_policy_.
   OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
   // The child policy config.
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
   // Child policy in state READY.
   bool child_policy_ready_ = false;
 };
@@ -561,7 +555,8 @@ const char* GrpcLb::Serverlist::ShouldDrop() {
 // GrpcLb::Picker
 //
 
-GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
+GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs args) {
+  PickResult result;
   // Check if we should drop the call.
   const char* drop_token = serverlist_->ShouldDrop();
   if (drop_token != nullptr) {
@@ -573,26 +568,28 @@ GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
     if (client_stats_ != nullptr) {
       client_stats_->AddCallDropped(drop_token);
     }
-    return PICK_COMPLETE;
+    result.type = PickResult::PICK_COMPLETE;
+    return result;
   }
   // Forward pick to child policy.
-  PickResult result = child_picker_->Pick(pick, error);
+  result = child_picker_->Pick(args);
   // If pick succeeded, add LB token to initial metadata.
-  if (result == PickResult::PICK_COMPLETE &&
-      pick->connected_subchannel != nullptr) {
+  if (result.type == PickResult::PICK_COMPLETE &&
+      result.connected_subchannel != nullptr) {
     const grpc_arg* arg = grpc_channel_args_find(
-        pick->connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
+        result.connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
     if (arg == nullptr) {
       gpr_log(GPR_ERROR,
-              "[grpclb %p picker %p] No LB token for connected subchannel "
-              "pick %p",
-              parent_, this, pick);
+              "[grpclb %p picker %p] No LB token for connected subchannel %p",
+              parent_, this, result.connected_subchannel.get());
       abort();
     }
     grpc_mdelem lb_token = {reinterpret_cast<uintptr_t>(arg->value.pointer.p)};
     GPR_ASSERT(!GRPC_MDISNULL(lb_token));
+    grpc_linked_mdelem* mdelem_storage = static_cast<grpc_linked_mdelem*>(
+        args.call_state->Alloc(sizeof(grpc_linked_mdelem)));
     GPR_ASSERT(grpc_metadata_batch_add_tail(
-                   pick->initial_metadata, &pick->lb_token_mdelem_storage,
+                   args.initial_metadata, mdelem_storage,
                    GRPC_MDELEM_REF(lb_token)) == GRPC_ERROR_NONE);
     GrpcLbClientStats* client_stats = static_cast<GrpcLbClientStats*>(
         grpc_mdelem_get_user_data(lb_token, GrpcLbClientStats::Destroy));
@@ -617,7 +614,8 @@ bool GrpcLb::Helper::CalledByCurrentChild() const {
   return child_ == parent_->child_policy_.get();
 }
 
-Subchannel* GrpcLb::Helper::CreateSubchannel(const grpc_channel_args& args) {
+RefCountedPtr<SubchannelInterface> GrpcLb::Helper::CreateSubchannel(
+    const grpc_channel_args& args) {
   if (parent_->shutting_down_ ||
       (!CalledByPendingChild() && !CalledByCurrentChild())) {
     return nullptr;
@@ -650,7 +648,6 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
     grpc_pollset_set_del_pollset_set(
         parent_->child_policy_->interested_parties(),
         parent_->interested_parties());
-    MutexLock lock(&parent_->child_policy_mu_);
     parent_->child_policy_ = std::move(parent_->pending_child_policy_);
   } else if (!CalledByCurrentChild()) {
     // This request is from an outdated child, so ignore it.
@@ -730,6 +727,15 @@ void GrpcLb::Helper::RequestReresolution() {
   }
 }
 
+void GrpcLb::Helper::AddTraceEvent(TraceSeverity severity,
+                                   const char* message) {
+  if (parent_->shutting_down_ ||
+      (!CalledByPendingChild() && !CalledByCurrentChild())) {
+    return;
+  }
+  parent_->channel_control_helper()->AddTraceEvent(severity, message);
+}
+
 //
 // GrpcLb::BalancerCallState
 //
@@ -1239,25 +1245,34 @@ grpc_channel_args* BuildBalancerChannelArgs(
       // treated as a stand-alone channel and not inherit this argument from the
       // args of the parent channel.
       GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+      // Don't want to pass down channelz node from parent; the balancer
+      // channel will get its own.
+      GRPC_ARG_CHANNELZ_CHANNEL_NODE,
   };
   // Channel args to add.
-  const grpc_arg args_to_add[] = {
-      // The fake resolver response generator, which we use to inject
-      // address updates into the LB channel.
+  InlinedVector<grpc_arg, 3> args_to_add;
+  // The fake resolver response generator, which we use to inject
+  // address updates into the LB channel.
+  args_to_add.emplace_back(
       grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
-          response_generator),
-      // A channel arg indicating the target is a grpclb load balancer.
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1),
-      // A channel arg indicating this is an internal channels, aka it is
-      // owned by components in Core, not by the user application.
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
-  };
+          response_generator));
+  // A channel arg indicating the target is a grpclb load balancer.
+  args_to_add.emplace_back(grpc_channel_arg_integer_create(
+      const_cast<char*>(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1));
+  // The parent channel's channelz uuid.
+  channelz::ChannelNode* channelz_node = nullptr;
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
+  if (arg != nullptr && arg->type == GRPC_ARG_POINTER &&
+      arg->value.pointer.p != nullptr) {
+    channelz_node = static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
+    args_to_add.emplace_back(
+        channelz::MakeParentUuidArg(channelz_node->uuid()));
+  }
   // Construct channel args.
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
-      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
-      GPR_ARRAY_SIZE(args_to_add));
+      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
+      args_to_add.size());
   // Make any necessary modifications for security.
   return grpc_lb_policy_grpclb_modify_lb_channel_args(addresses, new_args);
 }
@@ -1283,7 +1298,6 @@ GrpcLb::GrpcLb(Args args)
   GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_,
                     &GrpcLb::OnBalancerChannelConnectivityChangedLocked, this,
                     grpc_combiner_scheduler(args.combiner));
-  gpr_mu_init(&child_policy_mu_);
   // Record server name.
   const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI);
   const char* server_uri = grpc_channel_arg_get_string(arg);
@@ -1309,7 +1323,6 @@ GrpcLb::GrpcLb(Args args)
 GrpcLb::~GrpcLb() {
   gpr_free((void*)server_name_);
   grpc_channel_args_destroy(args_);
-  gpr_mu_destroy(&child_policy_mu_);
 }
 
 void GrpcLb::ShutdownLocked() {
@@ -1330,11 +1343,8 @@ void GrpcLb::ShutdownLocked() {
     grpc_pollset_set_del_pollset_set(
         pending_child_policy_->interested_parties(), interested_parties());
   }
-  {
-    MutexLock lock(&child_policy_mu_);
-    child_policy_.reset();
-    pending_child_policy_.reset();
-  }
+  child_policy_.reset();
+  pending_child_policy_.reset();
   // We destroy the LB channel here instead of in our destructor because
   // destroying the channel triggers a last callback to
   // OnBalancerChannelConnectivityChangedLocked(), and we need to be
@@ -1342,7 +1352,6 @@ void GrpcLb::ShutdownLocked() {
   if (lb_channel_ != nullptr) {
     grpc_channel_destroy(lb_channel_);
     lb_channel_ = nullptr;
-    gpr_atm_no_barrier_store(&lb_channel_uuid_, 0);
   }
 }
 
@@ -1362,29 +1371,6 @@ void GrpcLb::ResetBackoffLocked() {
   }
 }
 
-void GrpcLb::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels,
-    channelz::ChildRefsList* child_channels) {
-  {
-    // Delegate to the child policy to fill the children subchannels.
-    // This must be done holding child_policy_mu_, since this method
-    // does not run in the combiner.
-    MutexLock lock(&child_policy_mu_);
-    if (child_policy_ != nullptr) {
-      child_policy_->FillChildRefsForChannelz(child_subchannels,
-                                              child_channels);
-    }
-    if (pending_child_policy_ != nullptr) {
-      pending_child_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                      child_channels);
-    }
-  }
-  gpr_atm uuid = gpr_atm_no_barrier_load(&lb_channel_uuid_);
-  if (uuid != 0) {
-    child_channels->push_back(uuid);
-  }
-}
-
 void GrpcLb::UpdateLocked(UpdateArgs args) {
   const bool is_initial_update = lb_channel_ == nullptr;
   auto* grpclb_config =
@@ -1467,11 +1453,6 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked(
     lb_channel_ =
         channel_control_helper()->CreateChannel(uri_str, *lb_channel_args);
     GPR_ASSERT(lb_channel_ != nullptr);
-    grpc_core::channelz::ChannelNode* channel_node =
-        grpc_channel_get_channelz_node(lb_channel_);
-    if (channel_node != nullptr) {
-      gpr_atm_no_barrier_store(&lb_channel_uuid_, channel_node->uuid());
-    }
     gpr_free(uri_str);
   }
   // Propagate updates to the LB channel (pick_first) through the fake
@@ -1759,15 +1740,10 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() {
       gpr_log(GPR_INFO, "[grpclb %p] Creating new %schild policy %s", this,
               child_policy_ == nullptr ? "" : "pending ", child_policy_name);
     }
-    auto new_policy =
-        CreateChildPolicyLocked(child_policy_name, update_args.args);
     // Swap the policy into place.
     auto& lb_policy =
         child_policy_ == nullptr ? child_policy_ : pending_child_policy_;
-    {
-      MutexLock lock(&child_policy_mu_);
-      lb_policy = std::move(new_policy);
-    }
+    lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args);
     policy_to_update = lb_policy.get();
   } else {
     // Cases 2a and 3a: update an existing policy.
@@ -1800,15 +1776,15 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
 
   const char* name() const override { return kGrpclb; }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json == nullptr) {
-      return RefCountedPtr<ParsedLoadBalancingConfig>(
+      return RefCountedPtr<LoadBalancingPolicy::Config>(
           New<ParsedGrpcLbConfig>(nullptr));
     }
     InlinedVector<grpc_error*, 2> error_list;
-    RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
+    RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
     for (const grpc_json* field = json->child; field != nullptr;
          field = field->next) {
       if (field->key == nullptr) continue;
@@ -1826,7 +1802,7 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
       }
     }
     if (error_list.empty()) {
-      return RefCountedPtr<ParsedLoadBalancingConfig>(
+      return RefCountedPtr<LoadBalancingPolicy::Config>(
           New<ParsedGrpcLbConfig>(std::move(child_policy)));
     } else {
       *error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list);
index b51db11..22cefc9 100644 (file)
@@ -67,8 +67,12 @@ grpc_grpclb_request* grpc_grpclb_request_create(const char* lb_service_name) {
   req->has_client_stats = false;
   req->has_initial_request = true;
   req->initial_request.has_name = true;
-  strncpy(req->initial_request.name, lb_service_name,
-          GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH);
+  // GCC warns (-Wstringop-truncation) because the destination
+  // buffer size is identical to max-size, leading to a potential
+  // char[] with no null terminator.  nanopb can handle it fine,
+  // and parantheses around strncpy silence that compiler warning.
+  (strncpy(req->initial_request.name, lb_service_name,
+           GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH));
   return req;
 }
 
index bc2f6e5..00036d8 100644 (file)
@@ -53,8 +53,6 @@ class PickFirst : public LoadBalancingPolicy {
   void UpdateLocked(UpdateArgs args) override;
   void ExitIdleLocked() override;
   void ResetBackoffLocked() override;
-  void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                channelz::ChildRefsList* ignored) override;
 
  private:
   ~PickFirst();
@@ -68,9 +66,9 @@ class PickFirst : public LoadBalancingPolicy {
     PickFirstSubchannelData(
         SubchannelList<PickFirstSubchannelList, PickFirstSubchannelData>*
             subchannel_list,
-        const ServerAddress& address, Subchannel* subchannel,
-        grpc_combiner* combiner)
-        : SubchannelData(subchannel_list, address, subchannel, combiner) {}
+        const ServerAddress& address,
+        RefCountedPtr<SubchannelInterface> subchannel)
+        : SubchannelData(subchannel_list, address, std::move(subchannel)) {}
 
     void ProcessConnectivityChangeLocked(
         grpc_connectivity_state connectivity_state) override;
@@ -113,34 +111,23 @@ class PickFirst : public LoadBalancingPolicy {
 
   class Picker : public SubchannelPicker {
    public:
-    explicit Picker(RefCountedPtr<ConnectedSubchannel> connected_subchannel)
+    explicit Picker(
+        RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
         : connected_subchannel_(std::move(connected_subchannel)) {}
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override {
-      pick->connected_subchannel = connected_subchannel_;
-      return PICK_COMPLETE;
+    PickResult Pick(PickArgs args) override {
+      PickResult result;
+      result.type = PickResult::PICK_COMPLETE;
+      result.connected_subchannel = connected_subchannel_;
+      return result;
     }
 
    private:
-    RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-  };
-
-  // Helper class to ensure that any function that modifies the child refs
-  // data structures will update the channelz snapshot data structures before
-  // returning.
-  class AutoChildRefsUpdater {
-   public:
-    explicit AutoChildRefsUpdater(PickFirst* pf) : pf_(pf) {}
-    ~AutoChildRefsUpdater() { pf_->UpdateChildRefsLocked(); }
-
-   private:
-    PickFirst* pf_;
+    RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
   };
 
   void ShutdownLocked() override;
 
-  void UpdateChildRefsLocked();
-
   // All our subchannels.
   OrphanablePtr<PickFirstSubchannelList> subchannel_list_;
   // Latest pending subchannel list.
@@ -151,12 +138,6 @@ class PickFirst : public LoadBalancingPolicy {
   bool idle_ = false;
   // Are we shut down?
   bool shutdown_ = false;
-
-  /// Lock and data used to capture snapshots of this channels child
-  /// channels and subchannels. This data is consumed by channelz.
-  Mutex child_refs_mu_;
-  channelz::ChildRefsList child_subchannels_;
-  channelz::ChildRefsList child_channels_;
 };
 
 PickFirst::PickFirst(Args args) : LoadBalancingPolicy(std::move(args)) {
@@ -174,7 +155,6 @@ PickFirst::~PickFirst() {
 }
 
 void PickFirst::ShutdownLocked() {
-  AutoChildRefsUpdater guard(this);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
     gpr_log(GPR_INFO, "Pick First %p Shutting down", this);
   }
@@ -209,42 +189,7 @@ void PickFirst::ResetBackoffLocked() {
   }
 }
 
-void PickFirst::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels_to_fill,
-    channelz::ChildRefsList* ignored) {
-  MutexLock lock(&child_refs_mu_);
-  for (size_t i = 0; i < child_subchannels_.size(); ++i) {
-    // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
-    // have to implement lightweight set. For now, we don't care about
-    // performance when channelz requests are made.
-    bool found = false;
-    for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) {
-      if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) {
-        found = true;
-        break;
-      }
-    }
-    if (!found) {
-      child_subchannels_to_fill->push_back(child_subchannels_[i]);
-    }
-  }
-}
-
-void PickFirst::UpdateChildRefsLocked() {
-  channelz::ChildRefsList cs;
-  if (subchannel_list_ != nullptr) {
-    subchannel_list_->PopulateChildRefsList(&cs);
-  }
-  if (latest_pending_subchannel_list_ != nullptr) {
-    latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
-  }
-  // atomically update the data that channelz will actually be looking at.
-  MutexLock lock(&child_refs_mu_);
-  child_subchannels_ = std::move(cs);
-}
-
 void PickFirst::UpdateLocked(UpdateArgs args) {
-  AutoChildRefsUpdater guard(this);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
     gpr_log(GPR_INFO,
             "Pick First %p received update with %" PRIuPTR " addresses", this,
@@ -312,6 +257,7 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
       // here, since we've already checked the initial connectivity
       // state of all subchannels above.
       subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
+      subchannel_list_->subchannel(0)->subchannel()->AttemptToConnect();
     }
   } else {
     // We do have a selected subchannel (which means it's READY), so keep
@@ -334,6 +280,9 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
       // state of all subchannels above.
       latest_pending_subchannel_list_->subchannel(0)
           ->StartConnectivityWatchLocked();
+      latest_pending_subchannel_list_->subchannel(0)
+          ->subchannel()
+          ->AttemptToConnect();
     }
   }
 }
@@ -341,7 +290,6 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
 void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
     grpc_connectivity_state connectivity_state) {
   PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
-  AutoChildRefsUpdater guard(p);
   // The notification must be for a subchannel in either the current or
   // latest pending subchannel lists.
   GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() ||
@@ -366,7 +314,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
                 p->subchannel_list_.get());
       }
       p->selected_ = nullptr;
-      StopConnectivityWatchLocked();
+      CancelConnectivityWatchLocked(
+          "selected subchannel failed; switching to pending update");
       p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
       // Set our state to that of the pending subchannel list.
       if (p->subchannel_list_->in_transient_failure()) {
@@ -380,7 +329,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
       } else {
         p->channel_control_helper()->UpdateState(
             GRPC_CHANNEL_CONNECTING,
-            UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
+            UniquePtr<SubchannelPicker>(
+                New<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker"))));
       }
     } else {
       if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
@@ -391,10 +341,10 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
         p->idle_ = true;
         p->channel_control_helper()->RequestReresolution();
         p->selected_ = nullptr;
-        StopConnectivityWatchLocked();
+        CancelConnectivityWatchLocked("selected subchannel failed; going IDLE");
         p->channel_control_helper()->UpdateState(
-            GRPC_CHANNEL_IDLE,
-            UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
+            GRPC_CHANNEL_IDLE, UniquePtr<SubchannelPicker>(New<QueuePicker>(
+                                   p->Ref(DEBUG_LOCATION, "QueuePicker"))));
       } else {
         // This is unlikely but can happen when a subchannel has been asked
         // to reconnect by a different channel and this channel has dropped
@@ -405,11 +355,9 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
                                       connected_subchannel()->Ref())));
         } else {  // CONNECTING
           p->channel_control_helper()->UpdateState(
-              connectivity_state,
-              UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
+              connectivity_state, UniquePtr<SubchannelPicker>(New<QueuePicker>(
+                                      p->Ref(DEBUG_LOCATION, "QueuePicker"))));
         }
-        // Renew notification.
-        RenewConnectivityWatchLocked();
       }
     }
     return;
@@ -426,13 +374,11 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
   subchannel_list()->set_in_transient_failure(false);
   switch (connectivity_state) {
     case GRPC_CHANNEL_READY: {
-      // Renew notification.
-      RenewConnectivityWatchLocked();
       ProcessUnselectedReadyLocked();
       break;
     }
     case GRPC_CHANNEL_TRANSIENT_FAILURE: {
-      StopConnectivityWatchLocked();
+      CancelConnectivityWatchLocked("connection attempt failed");
       PickFirstSubchannelData* sd = this;
       size_t next_index =
           (sd->Index() + 1) % subchannel_list()->num_subchannels();
@@ -466,10 +412,9 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
       if (subchannel_list() == p->subchannel_list_.get()) {
         p->channel_control_helper()->UpdateState(
             GRPC_CHANNEL_CONNECTING,
-            UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
+            UniquePtr<SubchannelPicker>(
+                New<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker"))));
       }
-      // Renew notification.
-      RenewConnectivityWatchLocked();
       break;
     }
     case GRPC_CHANNEL_SHUTDOWN:
@@ -521,12 +466,15 @@ void PickFirst::PickFirstSubchannelData::
   // If current state is READY, select the subchannel now, since we started
   // watching from this state and will not get a notification of it
   // transitioning into this state.
-  if (p->selected_ != this && current_state == GRPC_CHANNEL_READY) {
-    ProcessUnselectedReadyLocked();
+  // If the current state is not READY, attempt to connect.
+  if (current_state == GRPC_CHANNEL_READY) {
+    if (p->selected_ != this) ProcessUnselectedReadyLocked();
+  } else {
+    subchannel()->AttemptToConnect();
   }
 }
 
-class ParsedPickFirstConfig : public ParsedLoadBalancingConfig {
+class ParsedPickFirstConfig : public LoadBalancingPolicy::Config {
  public:
   const char* name() const override { return kPickFirst; }
 };
@@ -544,12 +492,12 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
 
   const char* name() const override { return kPickFirst; }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error) const override {
     if (json != nullptr) {
       GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
     }
-    return RefCountedPtr<ParsedLoadBalancingConfig>(
+    return RefCountedPtr<LoadBalancingPolicy::Config>(
         New<ParsedPickFirstConfig>());
   }
 };
index 6d60391..c6655c7 100644 (file)
@@ -63,8 +63,6 @@ class RoundRobin : public LoadBalancingPolicy {
 
   void UpdateLocked(UpdateArgs args) override;
   void ResetBackoffLocked() override;
-  void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                channelz::ChildRefsList* ignored) override;
 
  private:
   ~RoundRobin();
@@ -83,9 +81,9 @@ class RoundRobin : public LoadBalancingPolicy {
     RoundRobinSubchannelData(
         SubchannelList<RoundRobinSubchannelList, RoundRobinSubchannelData>*
             subchannel_list,
-        const ServerAddress& address, Subchannel* subchannel,
-        grpc_combiner* combiner)
-        : SubchannelData(subchannel_list, address, subchannel, combiner) {}
+        const ServerAddress& address,
+        RefCountedPtr<SubchannelInterface> subchannel)
+        : SubchannelData(subchannel_list, address, std::move(subchannel)) {}
 
     grpc_connectivity_state connectivity_state() const {
       return last_connectivity_state_;
@@ -150,32 +148,18 @@ class RoundRobin : public LoadBalancingPolicy {
    public:
     Picker(RoundRobin* parent, RoundRobinSubchannelList* subchannel_list);
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override;
+    PickResult Pick(PickArgs args) override;
 
    private:
     // Using pointer value only, no ref held -- do not dereference!
     RoundRobin* parent_;
 
     size_t last_picked_index_;
-    InlinedVector<RefCountedPtr<ConnectedSubchannel>, 10> subchannels_;
-  };
-
-  // Helper class to ensure that any function that modifies the child refs
-  // data structures will update the channelz snapshot data structures before
-  // returning.
-  class AutoChildRefsUpdater {
-   public:
-    explicit AutoChildRefsUpdater(RoundRobin* rr) : rr_(rr) {}
-    ~AutoChildRefsUpdater() { rr_->UpdateChildRefsLocked(); }
-
-   private:
-    RoundRobin* rr_;
+    InlinedVector<RefCountedPtr<ConnectedSubchannelInterface>, 10> subchannels_;
   };
 
   void ShutdownLocked() override;
 
-  void UpdateChildRefsLocked();
-
   /** list of subchannels */
   OrphanablePtr<RoundRobinSubchannelList> subchannel_list_;
   /** Latest version of the subchannel list.
@@ -186,11 +170,6 @@ class RoundRobin : public LoadBalancingPolicy {
   OrphanablePtr<RoundRobinSubchannelList> latest_pending_subchannel_list_;
   /** are we shutting down? */
   bool shutdown_ = false;
-  /// Lock and data used to capture snapshots of this channel's child
-  /// channels and subchannels. This data is consumed by channelz.
-  Mutex child_refs_mu_;
-  channelz::ChildRefsList child_subchannels_;
-  channelz::ChildRefsList child_channels_;
 };
 
 //
@@ -221,8 +200,7 @@ RoundRobin::Picker::Picker(RoundRobin* parent,
   }
 }
 
-RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
-                                                grpc_error** error) {
+RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs args) {
   last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size();
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
     gpr_log(GPR_INFO,
@@ -231,8 +209,10 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
             parent_, this, last_picked_index_,
             subchannels_[last_picked_index_].get());
   }
-  pick->connected_subchannel = subchannels_[last_picked_index_];
-  return PICK_COMPLETE;
+  PickResult result;
+  result.type = PickResult::PICK_COMPLETE;
+  result.connected_subchannel = subchannels_[last_picked_index_];
+  return result;
 }
 
 //
@@ -254,7 +234,6 @@ RoundRobin::~RoundRobin() {
 }
 
 void RoundRobin::ShutdownLocked() {
-  AutoChildRefsUpdater guard(this);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
     gpr_log(GPR_INFO, "[RR %p] Shutting down", this);
   }
@@ -270,40 +249,6 @@ void RoundRobin::ResetBackoffLocked() {
   }
 }
 
-void RoundRobin::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels_to_fill,
-    channelz::ChildRefsList* ignored) {
-  MutexLock lock(&child_refs_mu_);
-  for (size_t i = 0; i < child_subchannels_.size(); ++i) {
-    // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
-    // have to implement lightweight set. For now, we don't care about
-    // performance when channelz requests are made.
-    bool found = false;
-    for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) {
-      if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) {
-        found = true;
-        break;
-      }
-    }
-    if (!found) {
-      child_subchannels_to_fill->push_back(child_subchannels_[i]);
-    }
-  }
-}
-
-void RoundRobin::UpdateChildRefsLocked() {
-  channelz::ChildRefsList cs;
-  if (subchannel_list_ != nullptr) {
-    subchannel_list_->PopulateChildRefsList(&cs);
-  }
-  if (latest_pending_subchannel_list_ != nullptr) {
-    latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
-  }
-  // atomically update the data that channelz will actually be looking at.
-  MutexLock lock(&child_refs_mu_);
-  child_subchannels_ = std::move(cs);
-}
-
 void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
   if (num_subchannels() == 0) return;
   // Check current state of each subchannel synchronously, since any
@@ -320,6 +265,7 @@ void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
   for (size_t i = 0; i < num_subchannels(); i++) {
     if (subchannel(i)->subchannel() != nullptr) {
       subchannel(i)->StartConnectivityWatchLocked();
+      subchannel(i)->subchannel()->AttemptToConnect();
     }
   }
   // Now set the LB policy's state based on the subchannels' states.
@@ -377,8 +323,8 @@ void RoundRobin::RoundRobinSubchannelList::
   } else if (num_connecting_ > 0) {
     /* 2) CONNECTING */
     p->channel_control_helper()->UpdateState(
-        GRPC_CHANNEL_CONNECTING,
-        UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
+        GRPC_CHANNEL_CONNECTING, UniquePtr<SubchannelPicker>(New<QueuePicker>(
+                                     p->Ref(DEBUG_LOCATION, "QueuePicker"))));
   } else if (num_transient_failure_ == num_subchannels()) {
     /* 3) TRANSIENT_FAILURE */
     grpc_error* error =
@@ -394,7 +340,6 @@ void RoundRobin::RoundRobinSubchannelList::
 void RoundRobin::RoundRobinSubchannelList::
     UpdateRoundRobinStateFromSubchannelStateCountsLocked() {
   RoundRobin* p = static_cast<RoundRobin*>(policy());
-  AutoChildRefsUpdater guard(p);
   if (num_ready_ > 0) {
     if (p->subchannel_list_.get() != this) {
       // Promote this list to p->subchannel_list_.
@@ -448,6 +393,7 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
   // Otherwise, if the subchannel was already in state TRANSIENT_FAILURE
   // when the subchannel list was created, we'd wind up in a constant
   // loop of re-resolution.
+  // Also attempt to reconnect.
   if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
       gpr_log(GPR_INFO,
@@ -456,9 +402,8 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
               p, subchannel());
     }
     p->channel_control_helper()->RequestReresolution();
+    subchannel()->AttemptToConnect();
   }
-  // Renew connectivity watch.
-  RenewConnectivityWatchLocked();
   // Update state counters.
   UpdateConnectivityStateLocked(connectivity_state);
   // Update overall state and renew notification.
@@ -466,7 +411,6 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
 }
 
 void RoundRobin::UpdateLocked(UpdateArgs args) {
-  AutoChildRefsUpdater guard(this);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
     gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses",
             this, args.addresses.size());
@@ -503,7 +447,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
   }
 }
 
-class ParsedRoundRobinConfig : public ParsedLoadBalancingConfig {
+class ParsedRoundRobinConfig : public LoadBalancingPolicy::Config {
  public:
   const char* name() const override { return kRoundRobin; }
 };
@@ -521,12 +465,12 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
 
   const char* name() const override { return kRoundRobin; }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error) const override {
     if (json != nullptr) {
       GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
     }
-    return RefCountedPtr<ParsedLoadBalancingConfig>(
+    return RefCountedPtr<LoadBalancingPolicy::Config>(
         New<ParsedRoundRobinConfig>());
   }
 };
index 4c48045..7d70928 100644 (file)
 
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+// TODO(roth): Should not need the include of subchannel.h here, since
+// that implementation should be hidden from the LB policy API.
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel_interface.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/abstract.h"
@@ -88,25 +91,23 @@ class SubchannelData {
   }
 
   // Returns a pointer to the subchannel.
-  Subchannel* subchannel() const { return subchannel_; }
+  SubchannelInterface* subchannel() const { return subchannel_.get(); }
 
   // Returns the connected subchannel.  Will be null if the subchannel
   // is not connected.
-  ConnectedSubchannel* connected_subchannel() const {
+  ConnectedSubchannelInterface* connected_subchannel() const {
     return connected_subchannel_.get();
   }
 
   // Synchronously checks the subchannel's connectivity state.
   // Must not be called while there is a connectivity notification
-  // pending (i.e., between calling StartConnectivityWatchLocked() or
-  // RenewConnectivityWatchLocked() and the resulting invocation of
-  // ProcessConnectivityChangeLocked()).
+  // pending (i.e., between calling StartConnectivityWatchLocked() and
+  // calling CancelConnectivityWatchLocked()).
   grpc_connectivity_state CheckConnectivityStateLocked() {
-    GPR_ASSERT(!connectivity_notification_pending_);
-    pending_connectivity_state_unsafe_ = subchannel()->CheckConnectivity(
-        subchannel_list_->inhibit_health_checking());
-    UpdateConnectedSubchannelLocked();
-    return pending_connectivity_state_unsafe_;
+    GPR_ASSERT(pending_watcher_ == nullptr);
+    connectivity_state_ =
+        subchannel()->CheckConnectivityState(&connected_subchannel_);
+    return connectivity_state_;
   }
 
   // Resets the connection backoff.
@@ -115,23 +116,11 @@ class SubchannelData {
   void ResetBackoffLocked();
 
   // Starts watching the connectivity state of the subchannel.
-  // ProcessConnectivityChangeLocked() will be called when the
+  // ProcessConnectivityChangeLocked() will be called whenever the
   // connectivity state changes.
   void StartConnectivityWatchLocked();
 
-  // Renews watching the connectivity state of the subchannel.
-  void RenewConnectivityWatchLocked();
-
-  // Stops watching the connectivity state of the subchannel.
-  void StopConnectivityWatchLocked();
-
   // Cancels watching the connectivity state of the subchannel.
-  // Must be called only while there is a connectivity notification
-  // pending (i.e., between calling StartConnectivityWatchLocked() or
-  // RenewConnectivityWatchLocked() and the resulting invocation of
-  // ProcessConnectivityChangeLocked()).
-  // From within ProcessConnectivityChangeLocked(), use
-  // StopConnectivityWatchLocked() instead.
   void CancelConnectivityWatchLocked(const char* reason);
 
   // Cancels any pending connectivity watch and unrefs the subchannel.
@@ -142,44 +131,81 @@ class SubchannelData {
  protected:
   SubchannelData(
       SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
-      const ServerAddress& address, Subchannel* subchannel,
-      grpc_combiner* combiner);
+      const ServerAddress& address,
+      RefCountedPtr<SubchannelInterface> subchannel);
 
   virtual ~SubchannelData();
 
-  // After StartConnectivityWatchLocked() or RenewConnectivityWatchLocked()
-  // is called, this method will be invoked when the subchannel's connectivity
-  // state changes.
-  // Implementations must invoke either RenewConnectivityWatchLocked() or
-  // StopConnectivityWatchLocked() before returning.
+  // After StartConnectivityWatchLocked() is called, this method will be
+  // invoked whenever the subchannel's connectivity state changes.
+  // To stop watching, use CancelConnectivityWatchLocked().
   virtual void ProcessConnectivityChangeLocked(
       grpc_connectivity_state connectivity_state) GRPC_ABSTRACT;
 
-  // Unrefs the subchannel.
-  void UnrefSubchannelLocked(const char* reason);
-
  private:
-  // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_.
-  // Returns true if the connectivity state should be reported.
-  bool UpdateConnectedSubchannelLocked();
+  // Watcher for subchannel connectivity state.
+  class Watcher : public SubchannelInterface::ConnectivityStateWatcher {
+   public:
+    Watcher(
+        SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data,
+        RefCountedPtr<SubchannelListType> subchannel_list)
+        : subchannel_data_(subchannel_data),
+          subchannel_list_(std::move(subchannel_list)) {}
+
+    ~Watcher() { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); }
+
+    void OnConnectivityStateChange(grpc_connectivity_state new_state,
+                                   RefCountedPtr<ConnectedSubchannelInterface>
+                                       connected_subchannel) override;
+
+    grpc_pollset_set* interested_parties() override {
+      return subchannel_list_->policy()->interested_parties();
+    }
+
+   private:
+    // A fire-and-forget class that bounces into the combiner to process
+    // a connectivity state update.
+    class Updater {
+     public:
+      Updater(
+          SubchannelData<SubchannelListType, SubchannelDataType>*
+              subchannel_data,
+          RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
+              subchannel_list,
+          grpc_connectivity_state state,
+          RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel);
+
+      ~Updater() {
+        subchannel_list_.reset(DEBUG_LOCATION, "Watcher::Updater dtor");
+      }
+
+     private:
+      static void OnUpdateLocked(void* arg, grpc_error* error);
+
+      SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data_;
+      RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
+          subchannel_list_;
+      const grpc_connectivity_state state_;
+      RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
+      grpc_closure closure_;
+    };
 
-  static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
+    SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data_;
+    RefCountedPtr<SubchannelListType> subchannel_list_;
+  };
+
+  // Unrefs the subchannel.
+  void UnrefSubchannelLocked(const char* reason);
 
   // Backpointer to owning subchannel list.  Not owned.
   SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list_;
-
-  // The subchannel and connected subchannel.
-  Subchannel* subchannel_;
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-
-  // Notification that connectivity has changed on subchannel.
-  grpc_closure connectivity_changed_closure_;
-  // Is a connectivity notification pending?
-  bool connectivity_notification_pending_ = false;
-  // Connectivity state to be updated by
-  // grpc_subchannel_notify_on_state_change(), not guarded by
-  // the combiner.
-  grpc_connectivity_state pending_connectivity_state_unsafe_;
+  // The subchannel.
+  RefCountedPtr<SubchannelInterface> subchannel_;
+  // Will be non-null when the subchannel's state is being watched.
+  SubchannelInterface::ConnectivityStateWatcher* pending_watcher_ = nullptr;
+  // Data updated by the watcher.
+  grpc_connectivity_state connectivity_state_;
+  RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
 };
 
 // A list of subchannels.
@@ -197,23 +223,9 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
   // Returns true if the subchannel list is shutting down.
   bool shutting_down() const { return shutting_down_; }
 
-  // Populates refs_list with the uuids of this SubchannelLists's subchannels.
-  void PopulateChildRefsList(channelz::ChildRefsList* refs_list) {
-    for (size_t i = 0; i < subchannels_.size(); ++i) {
-      if (subchannels_[i].subchannel() != nullptr) {
-        grpc_core::channelz::SubchannelNode* subchannel_node =
-            subchannels_[i].subchannel()->channelz_node();
-        if (subchannel_node != nullptr) {
-          refs_list->push_back(subchannel_node->uuid());
-        }
-      }
-    }
-  }
-
   // Accessors.
   LoadBalancingPolicy* policy() const { return policy_; }
   TraceFlag* tracer() const { return tracer_; }
-  bool inhibit_health_checking() const { return inhibit_health_checking_; }
 
   // Resets connection backoff of all subchannels.
   // TODO(roth): We will probably need to rethink this as part of moving
@@ -251,8 +263,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
 
   TraceFlag* tracer_;
 
-  bool inhibit_health_checking_;
-
   grpc_combiner* combiner_;
 
   // The list of subchannels.
@@ -269,29 +279,83 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
 //
 
 //
+// SubchannelData::Watcher
+//
+
+template <typename SubchannelListType, typename SubchannelDataType>
+void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::
+    OnConnectivityStateChange(
+        grpc_connectivity_state new_state,
+        RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel) {
+  // Will delete itself.
+  New<Updater>(subchannel_data_,
+               subchannel_list_->Ref(DEBUG_LOCATION, "Watcher::Updater"),
+               new_state, std::move(connected_subchannel));
+}
+
+template <typename SubchannelListType, typename SubchannelDataType>
+SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
+    Updater(
+        SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data,
+        RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
+            subchannel_list,
+        grpc_connectivity_state state,
+        RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
+    : subchannel_data_(subchannel_data),
+      subchannel_list_(std::move(subchannel_list)),
+      state_(state),
+      connected_subchannel_(std::move(connected_subchannel)) {
+  GRPC_CLOSURE_INIT(&closure_, &OnUpdateLocked, this,
+                    grpc_combiner_scheduler(subchannel_list_->combiner_));
+  GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
+}
+
+template <typename SubchannelListType, typename SubchannelDataType>
+void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
+    OnUpdateLocked(void* arg, grpc_error* error) {
+  Updater* self = static_cast<Updater*>(arg);
+  SubchannelData* sd = self->subchannel_data_;
+  if (GRPC_TRACE_FLAG_ENABLED(*sd->subchannel_list_->tracer())) {
+    gpr_log(GPR_INFO,
+            "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
+            " (subchannel %p): connectivity changed: state=%s, "
+            "connected_subchannel=%p, shutting_down=%d, pending_watcher=%p",
+            sd->subchannel_list_->tracer()->name(),
+            sd->subchannel_list_->policy(), sd->subchannel_list_, sd->Index(),
+            sd->subchannel_list_->num_subchannels(), sd->subchannel_.get(),
+            grpc_connectivity_state_name(self->state_),
+            self->connected_subchannel_.get(),
+            sd->subchannel_list_->shutting_down(), sd->pending_watcher_);
+  }
+  if (!sd->subchannel_list_->shutting_down() &&
+      sd->pending_watcher_ != nullptr) {
+    sd->connectivity_state_ = self->state_;
+    // Get or release ref to connected subchannel.
+    sd->connected_subchannel_ = std::move(self->connected_subchannel_);
+    // Call the subclass's ProcessConnectivityChangeLocked() method.
+    sd->ProcessConnectivityChangeLocked(sd->connectivity_state_);
+  }
+  // Clean up.
+  Delete(self);
+}
+
+//
 // SubchannelData
 //
 
 template <typename SubchannelListType, typename SubchannelDataType>
 SubchannelData<SubchannelListType, SubchannelDataType>::SubchannelData(
     SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
-    const ServerAddress& address, Subchannel* subchannel,
-    grpc_combiner* combiner)
+    const ServerAddress& address, RefCountedPtr<SubchannelInterface> subchannel)
     : subchannel_list_(subchannel_list),
-      subchannel_(subchannel),
+      subchannel_(std::move(subchannel)),
       // We assume that the current state is IDLE.  If not, we'll get a
       // callback telling us that.
-      pending_connectivity_state_unsafe_(GRPC_CHANNEL_IDLE) {
-  GRPC_CLOSURE_INIT(
-      &connectivity_changed_closure_,
-      (&SubchannelData<SubchannelListType,
-                       SubchannelDataType>::OnConnectivityChangedLocked),
-      this, grpc_combiner_scheduler(combiner));
-}
+      connectivity_state_(GRPC_CHANNEL_IDLE) {}
 
 template <typename SubchannelListType, typename SubchannelDataType>
 SubchannelData<SubchannelListType, SubchannelDataType>::~SubchannelData() {
-  UnrefSubchannelLocked("subchannel_data_destroy");
+  GPR_ASSERT(subchannel_ == nullptr);
 }
 
 template <typename SubchannelListType, typename SubchannelDataType>
@@ -304,10 +368,9 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
               " (subchannel %p): unreffing subchannel",
               subchannel_list_->tracer()->name(), subchannel_list_->policy(),
               subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-              subchannel_);
+              subchannel_.get());
     }
-    GRPC_SUBCHANNEL_UNREF(subchannel_, reason);
-    subchannel_ = nullptr;
+    subchannel_.reset();
     connected_subchannel_.reset();
   }
 }
@@ -326,56 +389,19 @@ void SubchannelData<SubchannelListType,
   if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) {
     gpr_log(GPR_INFO,
             "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-            " (subchannel %p): starting watch: requesting connectivity change "
-            "notification (from %s)",
+            " (subchannel %p): starting watch (from %s)",
             subchannel_list_->tracer()->name(), subchannel_list_->policy(),
             subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-            subchannel_,
-            grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
+            subchannel_.get(),
+            grpc_connectivity_state_name(connectivity_state_));
   }
-  GPR_ASSERT(!connectivity_notification_pending_);
-  connectivity_notification_pending_ = true;
-  subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release();
-  subchannel_->NotifyOnStateChange(
-      subchannel_list_->policy()->interested_parties(),
-      &pending_connectivity_state_unsafe_, &connectivity_changed_closure_,
-      subchannel_list_->inhibit_health_checking());
-}
-
-template <typename SubchannelListType, typename SubchannelDataType>
-void SubchannelData<SubchannelListType,
-                    SubchannelDataType>::RenewConnectivityWatchLocked() {
-  if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) {
-    gpr_log(GPR_INFO,
-            "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-            " (subchannel %p): renewing watch: requesting connectivity change "
-            "notification (from %s)",
-            subchannel_list_->tracer()->name(), subchannel_list_->policy(),
-            subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-            subchannel_,
-            grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
-  }
-  GPR_ASSERT(connectivity_notification_pending_);
-  subchannel_->NotifyOnStateChange(
-      subchannel_list_->policy()->interested_parties(),
-      &pending_connectivity_state_unsafe_, &connectivity_changed_closure_,
-      subchannel_list_->inhibit_health_checking());
-}
-
-template <typename SubchannelListType, typename SubchannelDataType>
-void SubchannelData<SubchannelListType,
-                    SubchannelDataType>::StopConnectivityWatchLocked() {
-  if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) {
-    gpr_log(GPR_INFO,
-            "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-            " (subchannel %p): stopping connectivity watch",
-            subchannel_list_->tracer()->name(), subchannel_list_->policy(),
-            subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-            subchannel_);
-  }
-  GPR_ASSERT(connectivity_notification_pending_);
-  connectivity_notification_pending_ = false;
-  subchannel_list()->Unref(DEBUG_LOCATION, "connectivity_watch");
+  GPR_ASSERT(pending_watcher_ == nullptr);
+  pending_watcher_ =
+      New<Watcher>(this, subchannel_list()->Ref(DEBUG_LOCATION, "Watcher"));
+  subchannel_->WatchConnectivityState(
+      connectivity_state_,
+      UniquePtr<SubchannelInterface::ConnectivityStateWatcher>(
+          pending_watcher_));
 }
 
 template <typename SubchannelListType, typename SubchannelDataType>
@@ -387,93 +413,18 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
             " (subchannel %p): canceling connectivity watch (%s)",
             subchannel_list_->tracer()->name(), subchannel_list_->policy(),
             subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-            subchannel_, reason);
-  }
-  GPR_ASSERT(connectivity_notification_pending_);
-  subchannel_->NotifyOnStateChange(nullptr, nullptr,
-                                   &connectivity_changed_closure_,
-                                   subchannel_list_->inhibit_health_checking());
-}
-
-template <typename SubchannelListType, typename SubchannelDataType>
-bool SubchannelData<SubchannelListType,
-                    SubchannelDataType>::UpdateConnectedSubchannelLocked() {
-  // If the subchannel is READY, take a ref to the connected subchannel.
-  if (pending_connectivity_state_unsafe_ == GRPC_CHANNEL_READY) {
-    connected_subchannel_ = subchannel_->connected_subchannel();
-    // If the subchannel became disconnected between the time that READY
-    // was reported and the time we got here (e.g., between when a
-    // notification callback is scheduled and when it was actually run in
-    // the combiner), then the connected subchannel may have disappeared out
-    // from under us.  In that case, we don't actually want to consider the
-    // subchannel to be in state READY.  Instead, we use IDLE as the
-    // basis for any future connectivity watch; this is the one state that
-    // the subchannel will never transition back into, so this ensures
-    // that we will get a notification for the next state, even if that state
-    // is READY again (e.g., if the subchannel has transitioned back to
-    // READY before the next watch gets requested).
-    if (connected_subchannel_ == nullptr) {
-      if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) {
-        gpr_log(GPR_INFO,
-                "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-                " (subchannel %p): state is READY but connected subchannel is "
-                "null; moving to state IDLE",
-                subchannel_list_->tracer()->name(), subchannel_list_->policy(),
-                subchannel_list_, Index(), subchannel_list_->num_subchannels(),
-                subchannel_);
-      }
-      pending_connectivity_state_unsafe_ = GRPC_CHANNEL_IDLE;
-      return false;
-    }
-  } else {
-    // For any state other than READY, unref the connected subchannel.
-    connected_subchannel_.reset();
+            subchannel_.get(), reason);
   }
-  return true;
-}
-
-template <typename SubchannelListType, typename SubchannelDataType>
-void SubchannelData<SubchannelListType, SubchannelDataType>::
-    OnConnectivityChangedLocked(void* arg, grpc_error* error) {
-  SubchannelData* sd = static_cast<SubchannelData*>(arg);
-  if (GRPC_TRACE_FLAG_ENABLED(*sd->subchannel_list_->tracer())) {
-    gpr_log(
-        GPR_INFO,
-        "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-        " (subchannel %p): connectivity changed: state=%s, error=%s, "
-        "shutting_down=%d",
-        sd->subchannel_list_->tracer()->name(), sd->subchannel_list_->policy(),
-        sd->subchannel_list_, sd->Index(),
-        sd->subchannel_list_->num_subchannels(), sd->subchannel_,
-        grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe_),
-        grpc_error_string(error), sd->subchannel_list_->shutting_down());
-  }
-  // If shutting down, unref subchannel and stop watching.
-  if (sd->subchannel_list_->shutting_down() || error == GRPC_ERROR_CANCELLED) {
-    sd->UnrefSubchannelLocked("connectivity_shutdown");
-    sd->StopConnectivityWatchLocked();
-    return;
+  if (pending_watcher_ != nullptr) {
+    subchannel_->CancelConnectivityStateWatch(pending_watcher_);
+    pending_watcher_ = nullptr;
   }
-  // Get or release ref to connected subchannel.
-  if (!sd->UpdateConnectedSubchannelLocked()) {
-    // We don't want to report this connectivity state, so renew the watch.
-    sd->RenewConnectivityWatchLocked();
-    return;
-  }
-  // Call the subclass's ProcessConnectivityChangeLocked() method.
-  sd->ProcessConnectivityChangeLocked(sd->pending_connectivity_state_unsafe_);
 }
 
 template <typename SubchannelListType, typename SubchannelDataType>
 void SubchannelData<SubchannelListType, SubchannelDataType>::ShutdownLocked() {
-  // If there's a pending notification for this subchannel, cancel it;
-  // the callback is responsible for unreffing the subchannel.
-  // Otherwise, unref the subchannel directly.
-  if (connectivity_notification_pending_) {
-    CancelConnectivityWatchLocked("shutdown");
-  } else if (subchannel_ != nullptr) {
-    UnrefSubchannelLocked("shutdown");
-  }
+  if (pending_watcher_ != nullptr) CancelConnectivityWatchLocked("shutdown");
+  UnrefSubchannelLocked("shutdown");
 }
 
 //
@@ -498,12 +449,10 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
   subchannels_.reserve(addresses.size());
   // We need to remove the LB addresses in order to be able to compare the
   // subchannel keys of subchannels from a different batch of addresses.
-  // We also remove the inhibit-health-checking arg, since we are
-  // handling that here.
-  inhibit_health_checking_ = grpc_channel_arg_get_bool(
-      grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
+  // We remove the service config, since it will be passed into the
+  // subchannel via call context.
   static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
-                                         GRPC_ARG_INHIBIT_HEALTH_CHECKING};
+                                         GRPC_ARG_SERVICE_CONFIG};
   // Create a subchannel for each address.
   for (size_t i = 0; i < addresses.size(); i++) {
     // TODO(roth): we should ideally hide this from the LB policy code. In
@@ -526,7 +475,8 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
         &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove),
         args_to_add.data(), args_to_add.size());
     gpr_free(args_to_add[subchannel_address_arg_index].value.string);
-    Subchannel* subchannel = helper->CreateSubchannel(*new_args);
+    RefCountedPtr<SubchannelInterface> subchannel =
+        helper->CreateSubchannel(*new_args);
     grpc_channel_args_destroy(new_args);
     if (subchannel == nullptr) {
       // Subchannel could not be created.
@@ -545,11 +495,11 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
       gpr_log(GPR_INFO,
               "[%s %p] subchannel list %p index %" PRIuPTR
               ": Created subchannel %p for address uri %s",
-              tracer_->name(), policy_, this, subchannels_.size(), subchannel,
-              address_uri);
+              tracer_->name(), policy_, this, subchannels_.size(),
+              subchannel.get(), address_uri);
       gpr_free(address_uri);
     }
-    subchannels_.emplace_back(this, addresses[i], subchannel, combiner);
+    subchannels_.emplace_back(this, addresses[i], std::move(subchannel));
   }
 }
 
index 3eb9437..e790ec2 100644 (file)
@@ -117,14 +117,16 @@ TraceFlag grpc_lb_xds_trace(false, "xds");
 namespace {
 
 constexpr char kXds[] = "xds_experimental";
-constexpr char kDefaultLocalityName[] = "xds_default_locality";
+constexpr char kDefaultLocalityRegion[] = "xds_default_locality_region";
+constexpr char kDefaultLocalityZone[] = "xds_default_locality_zone";
+constexpr char kDefaultLocalitySubzone[] = "xds_default_locality_subzone";
 constexpr uint32_t kDefaultLocalityWeight = 3;
 
-class ParsedXdsConfig : public ParsedLoadBalancingConfig {
+class ParsedXdsConfig : public LoadBalancingPolicy::Config {
  public:
   ParsedXdsConfig(const char* balancer_name,
-                  RefCountedPtr<ParsedLoadBalancingConfig> child_policy,
-                  RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy)
+                  RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
+                  RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy)
       : balancer_name_(balancer_name),
         child_policy_(std::move(child_policy)),
         fallback_policy_(std::move(fallback_policy)) {}
@@ -133,18 +135,18 @@ class ParsedXdsConfig : public ParsedLoadBalancingConfig {
 
   const char* balancer_name() const { return balancer_name_; };
 
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
     return child_policy_;
   }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy() const {
+  RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy() const {
     return fallback_policy_;
   }
 
  private:
   const char* balancer_name_ = nullptr;
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
-  RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_;
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
+  RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_;
 };
 
 class XdsLb : public LoadBalancingPolicy {
@@ -155,9 +157,6 @@ class XdsLb : public LoadBalancingPolicy {
 
   void UpdateLocked(UpdateArgs args) override;
   void ResetBackoffLocked() override;
-  void FillChildRefsForChannelz(
-      channelz::ChildRefsList* child_subchannels,
-      channelz::ChildRefsList* child_channels) override;
 
  private:
   struct LocalityServerlistEntry;
@@ -300,9 +299,7 @@ class XdsLb : public LoadBalancingPolicy {
    public:
     explicit PickerRef(UniquePtr<SubchannelPicker> picker)
         : picker_(std::move(picker)) {}
-    PickResult Pick(PickArgs* pick, grpc_error** error) {
-      return picker_->Pick(pick, error);
-    }
+    PickResult Pick(PickArgs args) { return picker_->Pick(args); }
 
    private:
     UniquePtr<SubchannelPicker> picker_;
@@ -322,12 +319,11 @@ class XdsLb : public LoadBalancingPolicy {
         : client_stats_(std::move(client_stats)),
           pickers_(std::move(pickers)) {}
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override;
+    PickResult Pick(PickArgs args) override;
 
    private:
     // Calls the picker of the locality that the key falls within
-    PickResult PickFromLocality(const uint32_t key, PickArgs* pick,
-                                grpc_error** error);
+    PickResult PickFromLocality(const uint32_t key, PickArgs args);
     RefCountedPtr<XdsLbClientStats> client_stats_;
     PickerList pickers_;
   };
@@ -337,12 +333,16 @@ class XdsLb : public LoadBalancingPolicy {
     explicit FallbackHelper(RefCountedPtr<XdsLb> parent)
         : parent_(std::move(parent)) {}
 
-    Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
+    ~FallbackHelper() { parent_.reset(DEBUG_LOCATION, "FallbackHelper"); }
+
+    RefCountedPtr<SubchannelInterface> CreateSubchannel(
+        const grpc_channel_args& args) override;
     grpc_channel* CreateChannel(const char* target,
                                 const grpc_channel_args& args) override;
     void UpdateState(grpc_connectivity_state state,
                      UniquePtr<SubchannelPicker> picker) override;
     void RequestReresolution() override;
+    void AddTraceEvent(TraceSeverity severity, const char* message) override;
 
     void set_child(LoadBalancingPolicy* child) { child_ = child; }
 
@@ -354,21 +354,61 @@ class XdsLb : public LoadBalancingPolicy {
     LoadBalancingPolicy* child_ = nullptr;
   };
 
+  class LocalityName : public RefCounted<LocalityName> {
+   public:
+    struct Less {
+      bool operator()(const RefCountedPtr<LocalityName>& lhs,
+                      const RefCountedPtr<LocalityName>& rhs) {
+        int cmp_result = strcmp(lhs->region_.get(), rhs->region_.get());
+        if (cmp_result != 0) return cmp_result < 0;
+        cmp_result = strcmp(lhs->zone_.get(), rhs->zone_.get());
+        if (cmp_result != 0) return cmp_result < 0;
+        return strcmp(lhs->subzone_.get(), rhs->subzone_.get()) < 0;
+      }
+    };
+
+    LocalityName(UniquePtr<char> region, UniquePtr<char> zone,
+                 UniquePtr<char> subzone)
+        : region_(std::move(region)),
+          zone_(std::move(zone)),
+          subzone_(std::move(subzone)) {}
+
+    bool operator==(const LocalityName& other) const {
+      return strcmp(region_.get(), other.region_.get()) == 0 &&
+             strcmp(zone_.get(), other.zone_.get()) == 0 &&
+             strcmp(subzone_.get(), other.subzone_.get()) == 0;
+    }
+
+    const char* AsHumanReadableString() {
+      if (human_readable_string_ == nullptr) {
+        char* tmp;
+        gpr_asprintf(&tmp, "{region=\"%s\", zone=\"%s\", subzone=\"%s\"}",
+                     region_.get(), zone_.get(), subzone_.get());
+        human_readable_string_.reset(tmp);
+      }
+      return human_readable_string_.get();
+    }
+
+   private:
+    UniquePtr<char> region_;
+    UniquePtr<char> zone_;
+    UniquePtr<char> subzone_;
+    UniquePtr<char> human_readable_string_;
+  };
+
   class LocalityMap {
    public:
     class LocalityEntry : public InternallyRefCounted<LocalityEntry> {
      public:
-      LocalityEntry(RefCountedPtr<XdsLb> parent, uint32_t locality_weight)
-          : parent_(std::move(parent)), locality_weight_(locality_weight) {}
-      ~LocalityEntry() = default;
+      LocalityEntry(RefCountedPtr<XdsLb> parent,
+                    RefCountedPtr<LocalityName> name, uint32_t locality_weight);
+      ~LocalityEntry();
 
       void UpdateLocked(xds_grpclb_serverlist* serverlist,
-                        ParsedLoadBalancingConfig* child_policy_config,
+                        LoadBalancingPolicy::Config* child_policy_config,
                         const grpc_channel_args* args);
       void ShutdownLocked();
       void ResetBackoffLocked();
-      void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                    channelz::ChildRefsList* child_channels);
       void Orphan() override;
 
      private:
@@ -377,12 +417,17 @@ class XdsLb : public LoadBalancingPolicy {
         explicit Helper(RefCountedPtr<LocalityEntry> entry)
             : entry_(std::move(entry)) {}
 
-        Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
+        ~Helper() { entry_.reset(DEBUG_LOCATION, "Helper"); }
+
+        RefCountedPtr<SubchannelInterface> CreateSubchannel(
+            const grpc_channel_args& args) override;
         grpc_channel* CreateChannel(const char* target,
                                     const grpc_channel_args& args) override;
         void UpdateState(grpc_connectivity_state state,
                          UniquePtr<SubchannelPicker> picker) override;
         void RequestReresolution() override;
+        void AddTraceEvent(TraceSeverity severity,
+                           const char* message) override;
         void set_child(LoadBalancingPolicy* child) { child_ = child; }
 
        private:
@@ -398,40 +443,32 @@ class XdsLb : public LoadBalancingPolicy {
       grpc_channel_args* CreateChildPolicyArgsLocked(
           const grpc_channel_args* args);
 
+      RefCountedPtr<XdsLb> parent_;
+      RefCountedPtr<LocalityName> name_;
       OrphanablePtr<LoadBalancingPolicy> child_policy_;
       OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
-      // Lock held when modifying the value of child_policy_ or
-      // pending_child_policy_.
-      Mutex child_policy_mu_;
-      RefCountedPtr<XdsLb> parent_;
       RefCountedPtr<PickerRef> picker_ref_;
       grpc_connectivity_state connectivity_state_;
       uint32_t locality_weight_;
     };
 
     void UpdateLocked(const LocalityList& locality_list,
-                      ParsedLoadBalancingConfig* child_policy_config,
+                      LoadBalancingPolicy::Config* child_policy_config,
                       const grpc_channel_args* args, XdsLb* parent);
     void ShutdownLocked();
     void ResetBackoffLocked();
-    void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                  channelz::ChildRefsList* child_channels);
 
    private:
     void PruneLocalities(const LocalityList& locality_list);
-    Map<UniquePtr<char>, OrphanablePtr<LocalityEntry>, StringLess> map_;
-    // Lock held while filling child refs for all localities
-    // inside the map
-    Mutex child_refs_mu_;
+    Map<RefCountedPtr<LocalityName>, OrphanablePtr<LocalityEntry>,
+        LocalityName::Less>
+        map_;
   };
 
   struct LocalityServerlistEntry {
-    ~LocalityServerlistEntry() {
-      gpr_free(locality_name);
-      xds_grpclb_destroy_serverlist(serverlist);
-    }
+    ~LocalityServerlistEntry() { xds_grpclb_destroy_serverlist(serverlist); }
 
-    char* locality_name;
+    RefCountedPtr<LocalityName> locality_name;
     uint32_t locality_weight;
     // The deserialized response from the balancer. May be nullptr until one
     // such response has arrived.
@@ -480,10 +517,6 @@ class XdsLb : public LoadBalancingPolicy {
   // The channel for communicating with the LB server.
   OrphanablePtr<BalancerChannelState> lb_chand_;
   OrphanablePtr<BalancerChannelState> pending_lb_chand_;
-  // Mutex to protect the channel to the LB server. This is used when
-  // processing a channelz request.
-  // TODO(juanlishen): Replace this with atomic.
-  Mutex lb_chand_mu_;
 
   // Timeout in milliseconds for the LB call. 0 means no deadline.
   int lb_call_timeout_ms_ = 0;
@@ -493,9 +526,8 @@ class XdsLb : public LoadBalancingPolicy {
   // 1. The fallback timer fires, we enter fallback mode.
   // 2. Before the fallback timer fires, the LB channel becomes
   // TRANSIENT_FAILURE or the LB call fails, we enter fallback mode.
-  // 3. Before the fallback timer fires, we receive a response from the
-  // balancer, we cancel the fallback timer and use the response to update the
-  // locality map.
+  // 3. Before the fallback timer fires, if any child policy in the locality map
+  // becomes READY, we cancel the fallback timer.
   bool fallback_at_startup_checks_pending_ = false;
   // Timeout in milliseconds for before using fallback backend addresses.
   // 0 means not using fallback.
@@ -507,16 +539,13 @@ class XdsLb : public LoadBalancingPolicy {
   grpc_closure lb_on_fallback_;
 
   // The policy to use for the fallback backends.
-  RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_config_;
-  // Lock held when modifying the value of fallback_policy_ or
-  // pending_fallback_policy_.
-  Mutex fallback_policy_mu_;
+  RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_config_;
   // Non-null iff we are in fallback mode.
   OrphanablePtr<LoadBalancingPolicy> fallback_policy_;
   OrphanablePtr<LoadBalancingPolicy> pending_fallback_policy_;
 
   // The policy to use for the backends.
-  RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
+  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
   // Map of policies to use in the backend
   LocalityMap locality_map_;
   // TODO(mhaidry) : Add support for multiple maps of localities
@@ -531,25 +560,24 @@ class XdsLb : public LoadBalancingPolicy {
 // XdsLb::Picker
 //
 
-XdsLb::PickResult XdsLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
+XdsLb::PickResult XdsLb::Picker::Pick(PickArgs args) {
   // TODO(roth): Add support for drop handling.
   // Generate a random number between 0 and the total weight
   const uint32_t key =
       (rand() * pickers_[pickers_.size() - 1].first) / RAND_MAX;
   // Forward pick to whichever locality maps to the range in which the
   // random number falls in.
-  PickResult result = PickFromLocality(key, pick, error);
+  PickResult result = PickFromLocality(key, args);
   // If pick succeeded, add client stats.
-  if (result == PickResult::PICK_COMPLETE &&
-      pick->connected_subchannel != nullptr && client_stats_ != nullptr) {
+  if (result.type == PickResult::PICK_COMPLETE &&
+      result.connected_subchannel != nullptr && client_stats_ != nullptr) {
     // TODO(roth): Add support for client stats.
   }
   return result;
 }
 
 XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
-                                                  PickArgs* pick,
-                                                  grpc_error** error) {
+                                                  PickArgs args) {
   size_t mid = 0;
   size_t start_index = 0;
   size_t end_index = pickers_.size() - 1;
@@ -567,7 +595,7 @@ XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
   }
   if (index == 0) index = start_index;
   GPR_ASSERT(pickers_[index].first > key);
-  return pickers_[index].second->Pick(pick, error);
+  return pickers_[index].second->Pick(args);
 }
 
 //
@@ -584,7 +612,7 @@ bool XdsLb::FallbackHelper::CalledByCurrentFallback() const {
   return child_ == parent_->fallback_policy_.get();
 }
 
-Subchannel* XdsLb::FallbackHelper::CreateSubchannel(
+RefCountedPtr<SubchannelInterface> XdsLb::FallbackHelper::CreateSubchannel(
     const grpc_channel_args& args) {
   if (parent_->shutting_down_ ||
       (!CalledByPendingFallback() && !CalledByCurrentFallback())) {
@@ -619,7 +647,6 @@ void XdsLb::FallbackHelper::UpdateState(grpc_connectivity_state state,
     grpc_pollset_set_del_pollset_set(
         parent_->fallback_policy_->interested_parties(),
         parent_->interested_parties());
-    MutexLock lock(&parent_->fallback_policy_mu_);
     parent_->fallback_policy_ = std::move(parent_->pending_fallback_policy_);
   } else if (!CalledByCurrentFallback()) {
     // This request is from an outdated fallback policy, so ignore it.
@@ -644,6 +671,15 @@ void XdsLb::FallbackHelper::RequestReresolution() {
   parent_->channel_control_helper()->RequestReresolution();
 }
 
+void XdsLb::FallbackHelper::AddTraceEvent(TraceSeverity severity,
+                                          const char* message) {
+  if (parent_->shutting_down_ ||
+      (!CalledByPendingFallback() && !CalledByCurrentFallback())) {
+    return;
+  }
+  parent_->channel_control_helper()->AddTraceEvent(severity, message);
+}
+
 //
 // serverlist parsing code
 //
@@ -723,7 +759,7 @@ ServerAddressList ProcessServerlist(const xds_grpclb_serverlist* serverlist) {
 
 XdsLb::BalancerChannelState::BalancerChannelState(
     const char* balancer_name, const grpc_channel_args& args,
-    grpc_core::RefCountedPtr<grpc_core::XdsLb> parent_xdslb_policy)
+    RefCountedPtr<XdsLb> parent_xdslb_policy)
     : InternallyRefCounted<BalancerChannelState>(&grpc_lb_xds_trace),
       xdslb_policy_(std::move(parent_xdslb_policy)),
       lb_call_backoff_(
@@ -743,6 +779,7 @@ XdsLb::BalancerChannelState::BalancerChannelState(
 }
 
 XdsLb::BalancerChannelState::~BalancerChannelState() {
+  xdslb_policy_.reset(DEBUG_LOCATION, "BalancerChannelState");
   grpc_channel_destroy(channel_);
 }
 
@@ -1197,15 +1234,15 @@ void XdsLb::BalancerChannelState::BalancerCallState::
         xds_grpclb_destroy_serverlist(
             xdslb_policy->locality_serverlist_[0]->serverlist);
       } else {
-        // This is the first serverlist we've received, don't enter fallback
-        // mode.
-        xdslb_policy->MaybeCancelFallbackAtStartupChecks();
         // Initialize locality serverlist, currently the list only handles
         // one child.
         xdslb_policy->locality_serverlist_.emplace_back(
             MakeUnique<LocalityServerlistEntry>());
         xdslb_policy->locality_serverlist_[0]->locality_name =
-            static_cast<char*>(gpr_strdup(kDefaultLocalityName));
+            MakeRefCounted<LocalityName>(
+                UniquePtr<char>(gpr_strdup(kDefaultLocalityRegion)),
+                UniquePtr<char>(gpr_strdup(kDefaultLocalityZone)),
+                UniquePtr<char>(gpr_strdup(kDefaultLocalitySubzone)));
         xdslb_policy->locality_serverlist_[0]->locality_weight =
             kDefaultLocalityWeight;
       }
@@ -1336,21 +1373,29 @@ grpc_channel_args* BuildBalancerChannelArgs(const grpc_channel_args* args) {
       // treated as a stand-alone channel and not inherit this argument from the
       // args of the parent channel.
       GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+      // Don't want to pass down channelz node from parent; the balancer
+      // channel will get its own.
+      GRPC_ARG_CHANNELZ_CHANNEL_NODE,
   };
   // Channel args to add.
-  const grpc_arg args_to_add[] = {
-      // 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
-      // owned by components in Core, not by the user application.
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
-  };
+  InlinedVector<grpc_arg, 2> args_to_add;
+  // A channel arg indicating the target is a xds load balancer.
+  args_to_add.emplace_back(grpc_channel_arg_integer_create(
+      const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1));
+  // The parent channel's channelz uuid.
+  channelz::ChannelNode* channelz_node = nullptr;
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
+  if (arg != nullptr && arg->type == GRPC_ARG_POINTER &&
+      arg->value.pointer.p != nullptr) {
+    channelz_node = static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
+    args_to_add.emplace_back(
+        channelz::MakeParentUuidArg(channelz_node->uuid()));
+  }
   // Construct channel args.
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
-      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
-      GPR_ARRAY_SIZE(args_to_add));
+      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
+      args_to_add.size());
   // Make any necessary modifications for security.
   return grpc_lb_policy_xds_modify_lb_channel_args(new_args);
 }
@@ -1386,12 +1431,18 @@ XdsLb::XdsLb(Args args)
 }
 
 XdsLb::~XdsLb() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
+    gpr_log(GPR_INFO, "[xdslb %p] destroying xds LB policy", this);
+  }
   gpr_free((void*)server_name_);
   grpc_channel_args_destroy(args_);
   locality_serverlist_.clear();
 }
 
 void XdsLb::ShutdownLocked() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
+    gpr_log(GPR_INFO, "[xdslb %p] shutting down", this);
+  }
   shutting_down_ = true;
   if (fallback_at_startup_checks_pending_) {
     grpc_timer_cancel(&lb_fallback_timer_);
@@ -1405,18 +1456,12 @@ void XdsLb::ShutdownLocked() {
     grpc_pollset_set_del_pollset_set(
         pending_fallback_policy_->interested_parties(), interested_parties());
   }
-  {
-    MutexLock lock(&fallback_policy_mu_);
-    fallback_policy_.reset();
-    pending_fallback_policy_.reset();
-  }
+  fallback_policy_.reset();
+  pending_fallback_policy_.reset();
   // We reset the LB channels here instead of in our destructor because they
   // hold refs to XdsLb.
-  {
-    MutexLock lock(&lb_chand_mu_);
-    lb_chand_.reset();
-    pending_lb_chand_.reset();
-  }
+  lb_chand_.reset();
+  pending_lb_chand_.reset();
 }
 
 //
@@ -1439,40 +1484,6 @@ void XdsLb::ResetBackoffLocked() {
   }
 }
 
-void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
-                                     channelz::ChildRefsList* child_channels) {
-  // Delegate to the locality_map_ to fill the children subchannels.
-  locality_map_.FillChildRefsForChannelz(child_subchannels, child_channels);
-  {
-    // This must be done holding fallback_policy_mu_, since this method does not
-    // run in the combiner.
-    MutexLock lock(&fallback_policy_mu_);
-    if (fallback_policy_ != nullptr) {
-      fallback_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                 child_channels);
-    }
-    if (pending_fallback_policy_ != nullptr) {
-      pending_fallback_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                         child_channels);
-    }
-  }
-  MutexLock lock(&lb_chand_mu_);
-  if (lb_chand_ != nullptr) {
-    grpc_core::channelz::ChannelNode* channel_node =
-        grpc_channel_get_channelz_node(lb_chand_->channel());
-    if (channel_node != nullptr) {
-      child_channels->push_back(channel_node->uuid());
-    }
-  }
-  if (pending_lb_chand_ != nullptr) {
-    grpc_core::channelz::ChannelNode* channel_node =
-        grpc_channel_get_channelz_node(pending_lb_chand_->channel());
-    if (channel_node != nullptr) {
-      child_channels->push_back(channel_node->uuid());
-    }
-  }
-}
-
 void XdsLb::ProcessAddressesAndChannelArgsLocked(
     const ServerAddressList& addresses, const grpc_channel_args& args) {
   // Update fallback address list.
@@ -1498,8 +1509,9 @@ void XdsLb::ProcessAddressesAndChannelArgsLocked(
   }
   if (create_lb_channel) {
     OrphanablePtr<BalancerChannelState> lb_chand =
-        MakeOrphanable<BalancerChannelState>(balancer_name_.get(),
-                                             *lb_channel_args, Ref());
+        MakeOrphanable<BalancerChannelState>(
+            balancer_name_.get(), *lb_channel_args,
+            Ref(DEBUG_LOCATION, "BalancerChannelState"));
     if (lb_chand_ == nullptr || !lb_chand_->HasActiveCall()) {
       GPR_ASSERT(pending_lb_chand_ == nullptr);
       // If we do not have a working LB channel yet, use the newly created one.
@@ -1662,14 +1674,10 @@ void XdsLb::UpdateFallbackPolicyLocked() {
               fallback_policy_ == nullptr ? "" : "pending ",
               fallback_policy_name);
     }
-    auto new_policy =
-        CreateFallbackPolicyLocked(fallback_policy_name, update_args.args);
     auto& lb_policy = fallback_policy_ == nullptr ? fallback_policy_
                                                   : pending_fallback_policy_;
-    {
-      MutexLock lock(&fallback_policy_mu_);
-      lb_policy = std::move(new_policy);
-    }
+    lb_policy =
+        CreateFallbackPolicyLocked(fallback_policy_name, update_args.args);
     policy_to_update = lb_policy.get();
   } else {
     // Cases 2a and 3a: update an existing policy.
@@ -1692,7 +1700,8 @@ void XdsLb::UpdateFallbackPolicyLocked() {
 
 OrphanablePtr<LoadBalancingPolicy> XdsLb::CreateFallbackPolicyLocked(
     const char* name, const grpc_channel_args* args) {
-  FallbackHelper* helper = New<FallbackHelper>(Ref());
+  FallbackHelper* helper =
+      New<FallbackHelper>(Ref(DEBUG_LOCATION, "FallbackHelper"));
   LoadBalancingPolicy::Args lb_policy_args;
   lb_policy_args.combiner = combiner();
   lb_policy_args.args = args;
@@ -1734,12 +1743,12 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
   for (auto iter = map_.begin(); iter != map_.end();) {
     bool found = false;
     for (size_t i = 0; i < locality_list.size(); i++) {
-      if (!gpr_stricmp(locality_list[i]->locality_name, iter->first.get())) {
+      if (*locality_list[i]->locality_name == *iter->first) {
         found = true;
+        break;
       }
     }
     if (!found) {  // Remove entries not present in the locality list
-      MutexLock lock(&child_refs_mu_);
       iter = map_.erase(iter);
     } else
       iter++;
@@ -1748,18 +1757,19 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
 
 void XdsLb::LocalityMap::UpdateLocked(
     const LocalityList& locality_serverlist,
-    ParsedLoadBalancingConfig* child_policy_config,
+    LoadBalancingPolicy::Config* child_policy_config,
     const grpc_channel_args* args, XdsLb* parent) {
   if (parent->shutting_down_) return;
   for (size_t i = 0; i < locality_serverlist.size(); i++) {
-    UniquePtr<char> locality_name(
-        gpr_strdup(locality_serverlist[i]->locality_name));
-    auto iter = map_.find(locality_name);
+    auto iter = map_.find(locality_serverlist[i]->locality_name);
     if (iter == map_.end()) {
       OrphanablePtr<LocalityEntry> new_entry = MakeOrphanable<LocalityEntry>(
-          parent->Ref(), locality_serverlist[i]->locality_weight);
-      MutexLock lock(&child_refs_mu_);
-      iter = map_.emplace(std::move(locality_name), std::move(new_entry)).first;
+          parent->Ref(DEBUG_LOCATION, "LocalityEntry"),
+          locality_serverlist[i]->locality_name,
+          locality_serverlist[i]->locality_weight);
+      iter = map_.emplace(locality_serverlist[i]->locality_name,
+                          std::move(new_entry))
+                 .first;
     }
     // Don't create new child policies if not directed to
     xds_grpclb_serverlist* serverlist =
@@ -1769,10 +1779,7 @@ void XdsLb::LocalityMap::UpdateLocked(
   PruneLocalities(locality_serverlist);
 }
 
-void XdsLb::LocalityMap::ShutdownLocked() {
-  MutexLock lock(&child_refs_mu_);
-  map_.clear();
-}
+void XdsLb::LocalityMap::ShutdownLocked() { map_.clear(); }
 
 void XdsLb::LocalityMap::ResetBackoffLocked() {
   for (auto& p : map_) {
@@ -1780,19 +1787,31 @@ void XdsLb::LocalityMap::ResetBackoffLocked() {
   }
 }
 
-void XdsLb::LocalityMap::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels,
-    channelz::ChildRefsList* child_channels) {
-  MutexLock lock(&child_refs_mu_);
-  for (auto& p : map_) {
-    p.second->FillChildRefsForChannelz(child_subchannels, child_channels);
-  }
-}
-
 //
 // XdsLb::LocalityMap::LocalityEntry
 //
 
+XdsLb::LocalityMap::LocalityEntry::LocalityEntry(
+    RefCountedPtr<XdsLb> parent, RefCountedPtr<LocalityName> name,
+    uint32_t locality_weight)
+    : parent_(std::move(parent)),
+      name_(std::move(name)),
+      locality_weight_(locality_weight) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
+    gpr_log(GPR_INFO, "[xdslb %p] created LocalityEntry %p for %s",
+            parent_.get(), this, name_->AsHumanReadableString());
+  }
+}
+
+XdsLb::LocalityMap::LocalityEntry::~LocalityEntry() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
+    gpr_log(GPR_INFO,
+            "[xdslb %p] LocalityEntry %p %s: destroying locality entry",
+            parent_.get(), this, name_->AsHumanReadableString());
+  }
+  parent_.reset(DEBUG_LOCATION, "LocalityEntry");
+}
+
 grpc_channel_args*
 XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked(
     const grpc_channel_args* args_in) {
@@ -1814,7 +1833,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked(
 OrphanablePtr<LoadBalancingPolicy>
 XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
     const char* name, const grpc_channel_args* args) {
-  Helper* helper = New<Helper>(this->Ref());
+  Helper* helper = New<Helper>(this->Ref(DEBUG_LOCATION, "Helper"));
   LoadBalancingPolicy::Args lb_policy_args;
   lb_policy_args.combiner = parent_->combiner();
   lb_policy_args.args = args;
@@ -1824,13 +1843,16 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
       LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
           name, std::move(lb_policy_args));
   if (GPR_UNLIKELY(lb_policy == nullptr)) {
-    gpr_log(GPR_ERROR, "[xdslb %p] Failure creating child policy %s", this,
-            name);
+    gpr_log(GPR_ERROR,
+            "[xdslb %p] LocalityEntry %p %s: failure creating child policy %s",
+            parent_.get(), this, name_->AsHumanReadableString(), name);
     return nullptr;
   }
   helper->set_child(lb_policy.get());
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
-    gpr_log(GPR_INFO, "[xdslb %p] Created new child policy %s (%p)", this, name,
+    gpr_log(GPR_INFO,
+            "[xdslb %p] LocalityEntry %p %s: Created new child policy %s (%p)",
+            parent_.get(), this, name_->AsHumanReadableString(), name,
             lb_policy.get());
   }
   // Add the xDS's interested_parties pollset_set to that of the newly created
@@ -1843,7 +1865,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
 
 void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
     xds_grpclb_serverlist* serverlist,
-    ParsedLoadBalancingConfig* child_policy_config,
+    LoadBalancingPolicy::Config* child_policy_config,
     const grpc_channel_args* args_in) {
   if (parent_->shutting_down_) return;
   // Construct update args.
@@ -1921,17 +1943,14 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
     // If child_policy_ is null, we set it (case 1), else we set
     // pending_child_policy_ (cases 2b and 3b).
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
-      gpr_log(GPR_INFO, "[xdslb %p] Creating new %schild policy %s", this,
+      gpr_log(GPR_INFO,
+              "[xdslb %p] LocalityEntry %p %s: Creating new %schild policy %s",
+              parent_.get(), this, name_->AsHumanReadableString(),
               child_policy_ == nullptr ? "" : "pending ", child_policy_name);
     }
-    auto new_policy =
-        CreateChildPolicyLocked(child_policy_name, update_args.args);
     auto& lb_policy =
         child_policy_ == nullptr ? child_policy_ : pending_child_policy_;
-    {
-      MutexLock lock(&child_policy_mu_);
-      lb_policy = std::move(new_policy);
-    }
+    lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args);
     policy_to_update = lb_policy.get();
   } else {
     // Cases 2a and 3a: update an existing policy.
@@ -1944,7 +1963,9 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
   GPR_ASSERT(policy_to_update != nullptr);
   // Update the policy.
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
-    gpr_log(GPR_INFO, "[xdslb %p] Updating %schild policy %p", this,
+    gpr_log(GPR_INFO,
+            "[xdslb %p] LocalityEntry %p %s: Updating %schild policy %p",
+            parent_.get(), this, name_->AsHumanReadableString(),
             policy_to_update == pending_child_policy_.get() ? "pending " : "",
             policy_to_update);
   }
@@ -1952,18 +1973,20 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
 }
 
 void XdsLb::LocalityMap::LocalityEntry::ShutdownLocked() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
+    gpr_log(GPR_INFO,
+            "[xdslb %p] LocalityEntry %p %s: shutting down locality entry",
+            parent_.get(), this, name_->AsHumanReadableString());
+  }
   // Remove the child policy's interested_parties pollset_set from the
   // xDS policy.
   grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(),
                                    parent_->interested_parties());
+  child_policy_.reset();
   if (pending_child_policy_ != nullptr) {
     grpc_pollset_set_del_pollset_set(
         pending_child_policy_->interested_parties(),
         parent_->interested_parties());
-  }
-  {
-    MutexLock lock(&child_policy_mu_);
-    child_policy_.reset();
     pending_child_policy_.reset();
   }
 }
@@ -1975,17 +1998,6 @@ void XdsLb::LocalityMap::LocalityEntry::ResetBackoffLocked() {
   }
 }
 
-void XdsLb::LocalityMap::LocalityEntry::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels,
-    channelz::ChildRefsList* child_channels) {
-  MutexLock lock(&child_policy_mu_);
-  child_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
-  if (pending_child_policy_ != nullptr) {
-    pending_child_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                    child_channels);
-  }
-}
-
 void XdsLb::LocalityMap::LocalityEntry::Orphan() {
   ShutdownLocked();
   Unref();
@@ -2005,7 +2017,8 @@ bool XdsLb::LocalityMap::LocalityEntry::Helper::CalledByCurrentChild() const {
   return child_ == entry_->child_policy_.get();
 }
 
-Subchannel* XdsLb::LocalityMap::LocalityEntry::Helper::CreateSubchannel(
+RefCountedPtr<SubchannelInterface>
+XdsLb::LocalityMap::LocalityEntry::Helper::CreateSubchannel(
     const grpc_channel_args& args) {
   if (entry_->parent_->shutting_down_ ||
       (!CalledByPendingChild() && !CalledByCurrentChild())) {
@@ -2039,14 +2052,16 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
     grpc_pollset_set_del_pollset_set(
         entry_->child_policy_->interested_parties(),
         entry_->parent_->interested_parties());
-    MutexLock lock(&entry_->child_policy_mu_);
     entry_->child_policy_ = std::move(entry_->pending_child_policy_);
   } else if (!CalledByCurrentChild()) {
     // This request is from an outdated child, so ignore it.
     return;
   }
   // At this point, child_ must be the current child policy.
-  if (state == GRPC_CHANNEL_READY) entry_->parent_->MaybeExitFallbackMode();
+  if (state == GRPC_CHANNEL_READY) {
+    entry_->parent_->MaybeCancelFallbackAtStartupChecks();
+    entry_->parent_->MaybeExitFallbackMode();
+  }
   // If we are in fallback mode, ignore update request from the child policy.
   if (entry_->parent_->fallback_policy_ != nullptr) return;
   GPR_ASSERT(entry_->parent_->lb_chand_ != nullptr);
@@ -2106,11 +2121,13 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
   } else if (num_connecting > 0) {
     entry_->parent_->channel_control_helper()->UpdateState(
         GRPC_CHANNEL_CONNECTING,
-        UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
+        UniquePtr<SubchannelPicker>(New<QueuePicker>(
+            this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker"))));
   } else if (num_idle > 0) {
     entry_->parent_->channel_control_helper()->UpdateState(
         GRPC_CHANNEL_IDLE,
-        UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
+        UniquePtr<SubchannelPicker>(New<QueuePicker>(
+            this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker"))));
   } else {
     GPR_ASSERT(num_transient_failures == locality_map.size());
     grpc_error* error =
@@ -2146,6 +2163,15 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() {
   }
 }
 
+void XdsLb::LocalityMap::LocalityEntry::Helper::AddTraceEvent(
+    TraceSeverity severity, const char* message) {
+  if (entry_->parent_->shutting_down_ ||
+      (!CalledByPendingChild() && !CalledByCurrentChild())) {
+    return;
+  }
+  entry_->parent_->channel_control_helper()->AddTraceEvent(severity, message);
+}
+
 //
 // factory
 //
@@ -2159,7 +2185,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
 
   const char* name() const override { return kXds; }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json == nullptr) {
@@ -2175,8 +2201,8 @@ class XdsFactory : public LoadBalancingPolicyFactory {
 
     InlinedVector<grpc_error*, 3> error_list;
     const char* balancer_name = nullptr;
-    RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
-    RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy;
+    RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
+    RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy;
     for (const grpc_json* field = json->child; field != nullptr;
          field = field->next) {
       if (field->key == nullptr) continue;
@@ -2222,7 +2248,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
           "field:balancerName error:not found"));
     }
     if (error_list.empty()) {
-      return RefCountedPtr<ParsedLoadBalancingConfig>(New<ParsedXdsConfig>(
+      return RefCountedPtr<LoadBalancingPolicy::Config>(New<ParsedXdsConfig>(
           balancer_name, std::move(child_policy), std::move(fallback_policy)));
     } else {
       *error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list);
index 9009497..58f26bf 100644 (file)
@@ -67,8 +67,12 @@ xds_grpclb_request* xds_grpclb_request_create(const char* lb_service_name) {
   req->has_client_stats = false;
   req->has_initial_request = true;
   req->initial_request.has_name = true;
-  strncpy(req->initial_request.name, lb_service_name,
-          XDS_SERVICE_NAME_MAX_LENGTH);
+  // GCC warns (-Wstringop-truncation) because the destination
+  // buffer size is identical to max-size, leading to a potential
+  // char[] with no null terminator.  nanopb can handle it fine,
+  // and parantheses around strncpy silence that compiler warning.
+  (strncpy(req->initial_request.name, lb_service_name,
+           XDS_SERVICE_NAME_MAX_LENGTH));
   return req;
 }
 
index aaf3e95..3b8c9fa 100644 (file)
@@ -37,7 +37,7 @@ class LoadBalancingPolicyFactory {
   /// Caller does NOT take ownership of result.
   virtual const char* name() const GRPC_ABSTRACT;
 
-  virtual RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error) const GRPC_ABSTRACT;
 
   virtual ~LoadBalancingPolicyFactory() {}
index 973aa26..20099b5 100644 (file)
@@ -176,7 +176,7 @@ grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
 }
 }  // namespace
 
-RefCountedPtr<ParsedLoadBalancingConfig>
+RefCountedPtr<LoadBalancingPolicy::Config>
 LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
                                                       grpc_error** error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
index 6820cfc..c5f0295 100644 (file)
@@ -56,7 +56,7 @@ class LoadBalancingPolicyRegistry {
 
   /// Returns a parsed object of the load balancing policy to be used from a
   /// LoadBalancingConfig array \a json.
-  static RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
+  static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
       const grpc_json* json, grpc_error** error);
 };
 
index 9aa5042..87a4442 100644 (file)
@@ -128,7 +128,7 @@ class Resolver : public InternallyRefCounted<Resolver> {
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
   /// Does NOT take ownership of the reference to \a combiner.
   // TODO(roth): Once we have a C++-like interface for combiners, this
index 0035873..32a339a 100644 (file)
@@ -473,10 +473,13 @@ static bool should_use_ares(const char* resolver_env) {
 }
 #endif /* GRPC_UV */
 
+static bool g_use_ares_dns_resolver;
+
 void grpc_resolver_dns_ares_init() {
   grpc_core::UniquePtr<char> resolver =
       GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
   if (should_use_ares(resolver.get())) {
+    g_use_ares_dns_resolver = true;
     gpr_log(GPR_DEBUG, "Using ares dns resolver");
     address_sorting_init();
     grpc_error* error = grpc_ares_init();
@@ -491,13 +494,13 @@ void grpc_resolver_dns_ares_init() {
     grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
         grpc_core::UniquePtr<grpc_core::ResolverFactory>(
             grpc_core::New<grpc_core::AresDnsResolverFactory>()));
+  } else {
+    g_use_ares_dns_resolver = false;
   }
 }
 
 void grpc_resolver_dns_ares_shutdown() {
-  grpc_core::UniquePtr<char> resolver =
-      GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
-  if (should_use_ares(resolver.get())) {
+  if (g_use_ares_dns_resolver) {
     address_sorting_shutdown();
     grpc_ares_cleanup();
   }
index 85f5cd8..7d52159 100644 (file)
@@ -231,7 +231,6 @@ class GrpcPolledFdWindows : public GrpcPolledFd {
 
   ares_ssize_t TrySendWriteBufSyncNonBlocking() {
     GPR_ASSERT(write_state_ == WRITE_IDLE);
-    ares_ssize_t total_sent;
     DWORD bytes_sent = 0;
     if (SendWriteBuf(&bytes_sent, nullptr) != 0) {
       int wsa_last_error = WSAGetLastError();
index 85b9bea..7f613ee 100644 (file)
@@ -175,11 +175,13 @@ void FakeResolverResponseGenerator::SetResponseLocked(void* arg,
   resolver->next_result_ = std::move(closure_arg->result);
   resolver->has_next_result_ = true;
   resolver->MaybeSendResultLocked();
+  closure_arg->generator->Unref();
   Delete(closure_arg);
 }
 
 void FakeResolverResponseGenerator::SetResponse(Resolver::Result result) {
   if (resolver_ != nullptr) {
+    Ref().release();  // ref to be held by closure
     SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
     closure_arg->generator = this;
     closure_arg->result = std::move(result);
index ac6bc7e..3a1960b 100644 (file)
@@ -92,11 +92,11 @@ bool ParseDuration(grpc_json* field, grpc_millis* duration) {
   return true;
 }
 
-UniquePtr<ClientChannelMethodParsedObject::RetryPolicy> ParseRetryPolicy(
+UniquePtr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
     grpc_json* field, grpc_error** error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   auto retry_policy =
-      MakeUnique<ClientChannelMethodParsedObject::RetryPolicy>();
+      MakeUnique<ClientChannelMethodParsedConfig::RetryPolicy>();
   if (field->type != GRPC_JSON_OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "field:retryPolicy error:should be of type object");
@@ -268,9 +268,9 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
                                                     grpc_error** error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   InlinedVector<grpc_error*, 4> error_list;
-  RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config;
+  RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
   UniquePtr<char> lb_policy_name;
-  Optional<ClientChannelGlobalParsedObject::RetryThrottling> retry_throttling;
+  Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling;
   const char* health_check_service_name = nullptr;
   for (grpc_json* field = json->child; field != nullptr; field = field->next) {
     if (field->key == nullptr) {
@@ -409,7 +409,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
           }
         }
       }
-      ClientChannelGlobalParsedObject::RetryThrottling data;
+      ClientChannelGlobalParsedConfig::RetryThrottling data;
       if (!max_milli_tokens.has_value()) {
         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             "field:retryThrottling field:maxTokens error:Not found"));
@@ -440,7 +440,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
                                          &error_list);
   if (*error == GRPC_ERROR_NONE) {
     return UniquePtr<ServiceConfig::ParsedConfig>(
-        New<ClientChannelGlobalParsedObject>(
+        New<ClientChannelGlobalParsedConfig>(
             std::move(parsed_lb_config), std::move(lb_policy_name),
             retry_throttling, health_check_service_name));
   }
@@ -454,7 +454,7 @@ ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json,
   InlinedVector<grpc_error*, 4> error_list;
   Optional<bool> wait_for_ready;
   grpc_millis timeout = 0;
-  UniquePtr<ClientChannelMethodParsedObject::RetryPolicy> retry_policy;
+  UniquePtr<ClientChannelMethodParsedConfig::RetryPolicy> retry_policy;
   for (grpc_json* field = json->child; field != nullptr; field = field->next) {
     if (field->key == nullptr) continue;
     if (strcmp(field->key, "waitForReady") == 0) {
@@ -494,7 +494,7 @@ ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json,
   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
   if (*error == GRPC_ERROR_NONE) {
     return UniquePtr<ServiceConfig::ParsedConfig>(
-        New<ClientChannelMethodParsedObject>(timeout, wait_for_ready,
+        New<ClientChannelMethodParsedConfig>(timeout, wait_for_ready,
                                              std::move(retry_policy)));
   }
   return nullptr;
index 9af8b16..d0a0456 100644 (file)
 namespace grpc_core {
 namespace internal {
 
-class ClientChannelGlobalParsedObject : public ServiceConfig::ParsedConfig {
+class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
  public:
   struct RetryThrottling {
     intptr_t max_milli_tokens = 0;
     intptr_t milli_token_ratio = 0;
   };
 
-  ClientChannelGlobalParsedObject(
-      RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config,
+  ClientChannelGlobalParsedConfig(
+      RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
       UniquePtr<char> parsed_deprecated_lb_policy,
       const Optional<RetryThrottling>& retry_throttling,
       const char* health_check_service_name)
@@ -58,7 +58,7 @@ class ClientChannelGlobalParsedObject : public ServiceConfig::ParsedConfig {
     return retry_throttling_;
   }
 
-  RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config() const {
+  RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
     return parsed_lb_config_;
   }
 
@@ -71,13 +71,13 @@ class ClientChannelGlobalParsedObject : public ServiceConfig::ParsedConfig {
   }
 
  private:
-  RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config_;
+  RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
   UniquePtr<char> parsed_deprecated_lb_policy_;
   Optional<RetryThrottling> retry_throttling_;
   const char* health_check_service_name_;
 };
 
-class ClientChannelMethodParsedObject : public ServiceConfig::ParsedConfig {
+class ClientChannelMethodParsedConfig : public ServiceConfig::ParsedConfig {
  public:
   struct RetryPolicy {
     int max_attempts = 0;
@@ -87,7 +87,7 @@ class ClientChannelMethodParsedObject : public ServiceConfig::ParsedConfig {
     StatusCodeSet retryable_status_codes;
   };
 
-  ClientChannelMethodParsedObject(grpc_millis timeout,
+  ClientChannelMethodParsedConfig(grpc_millis timeout,
                                   const Optional<bool>& wait_for_ready,
                                   UniquePtr<RetryPolicy> retry_policy)
       : timeout_(timeout),
index b6bc3ea..180b0fc 100644 (file)
@@ -106,7 +106,8 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
       RefCountedPtr<ResolvingLoadBalancingPolicy> parent)
       : parent_(std::move(parent)) {}
 
-  Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
+  RefCountedPtr<SubchannelInterface> CreateSubchannel(
+      const grpc_channel_args& args) override {
     if (parent_->resolver_ == nullptr) return nullptr;  // Shutting down.
     if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
     return parent_->channel_control_helper()->CreateSubchannel(args);
@@ -136,7 +137,6 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
       grpc_pollset_set_del_pollset_set(
           parent_->lb_policy_->interested_parties(),
           parent_->interested_parties());
-      MutexLock lock(&parent_->lb_policy_mu_);
       parent_->lb_policy_ = std::move(parent_->pending_lb_policy_);
     } else if (!CalledByCurrentChild()) {
       // This request is from an outdated child, so ignore it.
@@ -184,7 +184,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
 ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
     Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
     UniquePtr<char> child_policy_name,
-    RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
+    RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
     grpc_error** error)
     : LoadBalancingPolicy(std::move(args)),
       tracer_(tracer),
@@ -213,7 +213,6 @@ ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
       process_resolver_result_(process_resolver_result),
       process_resolver_result_user_data_(process_resolver_result_user_data) {
   GPR_ASSERT(process_resolver_result != nullptr);
-  gpr_mu_init(&lb_policy_mu_);
   *error = Init(*args.args);
 }
 
@@ -233,13 +232,11 @@ grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) {
 ResolvingLoadBalancingPolicy::~ResolvingLoadBalancingPolicy() {
   GPR_ASSERT(resolver_ == nullptr);
   GPR_ASSERT(lb_policy_ == nullptr);
-  gpr_mu_destroy(&lb_policy_mu_);
 }
 
 void ResolvingLoadBalancingPolicy::ShutdownLocked() {
   if (resolver_ != nullptr) {
     resolver_.reset();
-    MutexLock lock(&lb_policy_mu_);
     if (lb_policy_ != nullptr) {
       if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
         gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
@@ -281,22 +278,6 @@ void ResolvingLoadBalancingPolicy::ResetBackoffLocked() {
   if (pending_lb_policy_ != nullptr) pending_lb_policy_->ResetBackoffLocked();
 }
 
-void ResolvingLoadBalancingPolicy::FillChildRefsForChannelz(
-    channelz::ChildRefsList* child_subchannels,
-    channelz::ChildRefsList* child_channels) {
-  // Delegate to the lb_policy_ to fill the children subchannels.
-  // This must be done holding lb_policy_mu_, since this method does not
-  // run in the combiner.
-  MutexLock lock(&lb_policy_mu_);
-  if (lb_policy_ != nullptr) {
-    lb_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
-  }
-  if (pending_lb_policy_ != nullptr) {
-    pending_lb_policy_->FillChildRefsForChannelz(child_subchannels,
-                                                 child_channels);
-  }
-}
-
 void ResolvingLoadBalancingPolicy::StartResolvingLocked() {
   if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
     gpr_log(GPR_INFO, "resolving_lb=%p: starting name resolution", this);
@@ -333,7 +314,7 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
 
 void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
     const char* lb_policy_name,
-    RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
+    RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
     Resolver::Result result, TraceStringVector* trace_strings) {
   // If the child policy name changes, we need to create a new child
   // policy.  When this happens, we leave child_policy_ as-is and store
@@ -402,13 +383,9 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
       gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this,
               lb_policy_ == nullptr ? "" : "pending ", lb_policy_name);
     }
-    auto new_policy =
-        CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings);
     auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_;
-    {
-      MutexLock lock(&lb_policy_mu_);
-      lb_policy = std::move(new_policy);
-    }
+    lb_policy =
+        CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings);
     policy_to_update = lb_policy.get();
   } else {
     // Cases 2a and 3a: update an existing policy.
@@ -450,11 +427,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
           lb_policy_name, std::move(lb_policy_args));
   if (GPR_UNLIKELY(lb_policy == nullptr)) {
     gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
-    if (channelz_node() != nullptr) {
-      char* str;
-      gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
-      trace_strings->push_back(str);
-    }
+    char* str;
+    gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
+    trace_strings->push_back(str);
     return nullptr;
   }
   helper->set_child(lb_policy.get());
@@ -462,16 +437,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
     gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)",
             this, lb_policy_name, lb_policy.get());
   }
-  if (channelz_node() != nullptr) {
-    char* str;
-    gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
-    trace_strings->push_back(str);
-  }
-  // Propagate channelz node.
-  auto* channelz = channelz_node();
-  if (channelz != nullptr) {
-    lb_policy->set_channelz_node(channelz->Ref());
-  }
+  char* str;
+  gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
+  trace_strings->push_back(str);
   grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
                                    interested_parties());
   return lb_policy;
@@ -501,11 +469,10 @@ void ResolvingLoadBalancingPolicy::ConcatenateAndAddChannelTraceLocked(
       is_first = false;
       gpr_strvec_add(&v, (*trace_strings)[i]);
     }
-    char* flat;
-    size_t flat_len = 0;
-    flat = gpr_strvec_flatten(&v, &flat_len);
-    channelz_node()->AddTraceEvent(channelz::ChannelTrace::Severity::Info,
-                                   grpc_slice_new(flat, flat_len, gpr_free));
+    size_t len = 0;
+    UniquePtr<char> message(gpr_strvec_flatten(&v, &len));
+    channel_control_helper()->AddTraceEvent(ChannelControlHelper::TRACE_INFO,
+                                            message.get());
     gpr_strvec_destroy(&v);
   }
 }
@@ -530,7 +497,7 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
   const bool resolution_contains_addresses = result.addresses.size() > 0;
   // Process the resolver result.
   const char* lb_policy_name = nullptr;
-  RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config;
+  RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config;
   bool service_config_changed = false;
   char* service_config_error_string = nullptr;
   if (process_resolver_result_ != nullptr) {
@@ -559,21 +526,18 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
                                  std::move(result), &trace_strings);
   }
   // Add channel trace event.
-  if (channelz_node() != nullptr) {
-    if (service_config_changed) {
-      // TODO(ncteisen): might be worth somehow including a snippet of the
-      // config in the trace, at the risk of bloating the trace logs.
-      trace_strings.push_back(gpr_strdup("Service config changed"));
-    }
-    if (service_config_error_string != nullptr) {
-      trace_strings.push_back(service_config_error_string);
-      service_config_error_string = nullptr;
-    }
-    MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses,
-                                                 &trace_strings);
-    ConcatenateAndAddChannelTraceLocked(&trace_strings);
+  if (service_config_changed) {
+    // TODO(ncteisen): might be worth somehow including a snippet of the
+    // config in the trace, at the risk of bloating the trace logs.
+    trace_strings.push_back(gpr_strdup("Service config changed"));
+  }
+  if (service_config_error_string != nullptr) {
+    trace_strings.push_back(service_config_error_string);
+    service_config_error_string = nullptr;
   }
-  gpr_free(service_config_error_string);
+  MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses,
+                                               &trace_strings);
+  ConcatenateAndAddChannelTraceLocked(&trace_strings);
 }
 
 }  // namespace grpc_core
index b7d99dc..e91ea83 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
 #include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/resolver.h"
@@ -57,7 +56,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
   ResolvingLoadBalancingPolicy(
       Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
       UniquePtr<char> child_policy_name,
-      RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
+      RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
       grpc_error** error);
 
   // Private ctor, to be used by client_channel only!
@@ -71,7 +70,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
   typedef bool (*ProcessResolverResultCallback)(
       void* user_data, const Resolver::Result& result,
       const char** lb_policy_name,
-      RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
+      RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
       grpc_error** service_config_error);
   // If error is set when this returns, then construction failed, and
   // the caller may not use the new object.
@@ -91,10 +90,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
 
   void ResetBackoffLocked() override;
 
-  void FillChildRefsForChannelz(
-      channelz::ChildRefsList* child_subchannels,
-      channelz::ChildRefsList* child_channels) override;
-
  private:
   using TraceStringVector = InlinedVector<char*, 3>;
 
@@ -110,7 +105,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
   void OnResolverError(grpc_error* error);
   void CreateOrUpdateLbPolicyLocked(
       const char* lb_policy_name,
-      RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
+      RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
       Resolver::Result result, TraceStringVector* trace_strings);
   OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
       const char* lb_policy_name, const grpc_channel_args& args,
@@ -127,7 +122,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
   ProcessResolverResultCallback process_resolver_result_ = nullptr;
   void* process_resolver_result_user_data_ = nullptr;
   UniquePtr<char> child_policy_name_;
-  RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config_;
+  RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config_;
 
   // Resolver and associated state.
   OrphanablePtr<Resolver> resolver_;
@@ -137,9 +132,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
   // Child LB policy.
   OrphanablePtr<LoadBalancingPolicy> lb_policy_;
   OrphanablePtr<LoadBalancingPolicy> pending_lb_policy_;
-  // Lock held when modifying the value of child_policy_ or
-  // pending_child_policy_.
-  gpr_mu lb_policy_mu_;
 };
 
 }  // namespace grpc_core
index c2941af..31c0eda 100644 (file)
@@ -39,12 +39,10 @@ ServerAddress::ServerAddress(const void* address, size_t address_len,
   address_.len = static_cast<socklen_t>(address_len);
 }
 
-int ServerAddress::Cmp(const ServerAddress& other) const {
-  if (address_.len > other.address_.len) return 1;
-  if (address_.len < other.address_.len) return -1;
-  int retval = memcmp(address_.addr, other.address_.addr, address_.len);
-  if (retval != 0) return retval;
-  return grpc_channel_args_compare(args_, other.args_);
+bool ServerAddress::operator==(const grpc_core::ServerAddress& other) const {
+  return address_.len == other.address_.len &&
+         memcmp(address_.addr, other.address_.addr, address_.len) == 0 &&
+         grpc_channel_args_compare(args_, other.args_) == 0;
 }
 
 bool ServerAddress::IsBalancer() const {
index 040cd2e..1b68a59 100644 (file)
@@ -73,9 +73,7 @@ class ServerAddress {
     return *this;
   }
 
-  bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; }
-
-  int Cmp(const ServerAddress& other) const;
+  bool operator==(const ServerAddress& other) const;
 
   const grpc_resolved_address& address() const { return address_; }
   const grpc_channel_args* args() const { return args_; }
index 86d4f73..d41859b 100644 (file)
@@ -96,16 +96,15 @@ grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) {
     if (parser_error != GRPC_ERROR_NONE) {
       error_list.push_back(parser_error);
     }
-    parsed_global_service_config_objects_.push_back(std::move(parsed_obj));
+    parsed_global_configs_.push_back(std::move(parsed_obj));
   }
   return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list);
 }
 
-grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
+grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
     const grpc_json* json,
-    SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries,
-    size_t* idx) {
-  auto objs_vector = MakeUnique<ServiceConfigObjectsVector>();
+    SliceHashTable<const ParsedConfigVector*>::Entry* entries, size_t* idx) {
+  auto objs_vector = MakeUnique<ParsedConfigVector>();
   InlinedVector<grpc_error*, 4> error_list;
   for (size_t i = 0; i < g_registered_parsers->size(); i++) {
     grpc_error* parser_error = GRPC_ERROR_NONE;
@@ -116,10 +115,10 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
     }
     objs_vector->push_back(std::move(parsed_obj));
   }
-  service_config_objects_vectors_storage_.push_back(std::move(objs_vector));
+  parsed_method_config_vectors_storage_.push_back(std::move(objs_vector));
   const auto* vector_ptr =
-      service_config_objects_vectors_storage_
-          [service_config_objects_vectors_storage_.size() - 1]
+      parsed_method_config_vectors_storage_
+          [parsed_method_config_vectors_storage_.size() - 1]
               .get();
   // Construct list of paths.
   InlinedVector<UniquePtr<char>, 10> paths;
@@ -160,7 +159,7 @@ wrap_error:
 grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
   GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT);
   GPR_DEBUG_ASSERT(json_tree_->key == nullptr);
-  SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries = nullptr;
+  SliceHashTable<const ParsedConfigVector*>::Entry* entries = nullptr;
   size_t num_entries = 0;
   InlinedVector<grpc_error*, 4> error_list;
   for (grpc_json* field = json_tree->child; field != nullptr;
@@ -187,14 +186,13 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
         }
         num_entries += static_cast<size_t>(count);
       }
-      entries = static_cast<
-          SliceHashTable<const ServiceConfigObjectsVector*>::Entry*>(gpr_zalloc(
-          num_entries *
-          sizeof(SliceHashTable<const ServiceConfigObjectsVector*>::Entry)));
+      entries = static_cast<SliceHashTable<const ParsedConfigVector*>::Entry*>(
+          gpr_zalloc(num_entries *
+                     sizeof(SliceHashTable<const ParsedConfigVector*>::Entry)));
       size_t idx = 0;
       for (grpc_json* method = field->child; method != nullptr;
            method = method->next) {
-        grpc_error* error = ParseJsonMethodConfigToServiceConfigObjectsTable(
+        grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable(
             method, entries, &idx);
         if (error != GRPC_ERROR_NONE) {
           error_list.push_back(error);
@@ -206,9 +204,9 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
     }
   }
   if (entries != nullptr) {
-    parsed_method_service_config_objects_table_ =
-        SliceHashTable<const ServiceConfigObjectsVector*>::Create(
-            num_entries, entries, nullptr);
+    parsed_method_configs_table_ =
+        SliceHashTable<const ParsedConfigVector*>::Create(num_entries, entries,
+                                                          nullptr);
     gpr_free(entries);
   }
   return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
@@ -287,12 +285,12 @@ UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json,
   return UniquePtr<char>(path);
 }
 
-const ServiceConfig::ServiceConfigObjectsVector*
-ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) {
-  if (parsed_method_service_config_objects_table_.get() == nullptr) {
+const ServiceConfig::ParsedConfigVector*
+ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) {
+  if (parsed_method_configs_table_.get() == nullptr) {
     return nullptr;
   }
-  const auto* value = parsed_method_service_config_objects_table_->Get(path);
+  const auto* value = parsed_method_configs_table_->Get(path);
   // If we didn't find a match for the path, try looking for a wildcard
   // entry (i.e., change "/service/method" to "/service/*").
   if (value == nullptr) {
@@ -305,7 +303,7 @@ ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) {
     buf[len + 1] = '\0';
     grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
     gpr_free(buf);
-    value = parsed_method_service_config_objects_table_->Get(wildcard_path);
+    value = parsed_method_configs_table_->Get(wildcard_path);
     grpc_slice_unref_internal(wildcard_path);
     gpr_free(path_str);
     if (value == nullptr) return nullptr;
index e6f855a..189a0b9 100644 (file)
@@ -88,7 +88,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
 
   static constexpr int kNumPreallocatedParsers = 4;
   typedef InlinedVector<UniquePtr<ParsedConfig>, kNumPreallocatedParsers>
-      ServiceConfigObjectsVector;
+      ParsedConfigVector;
 
   /// When a service config is applied to a call in the client_channel_filter,
   /// we create an instance of this object and store it in the call_data for
@@ -102,25 +102,25 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
         : service_config_(std::move(svc_cfg)) {
       if (service_config_ != nullptr) {
         method_params_vector_ =
-            service_config_->GetMethodServiceConfigObjectsVector(path);
+            service_config_->GetMethodParsedConfigVector(path);
       }
     }
 
     ServiceConfig* service_config() { return service_config_.get(); }
 
-    ParsedConfig* GetMethodParsedObject(size_t index) const {
+    ParsedConfig* GetMethodParsedConfig(size_t index) const {
       return method_params_vector_ != nullptr
                  ? (*method_params_vector_)[index].get()
                  : nullptr;
     }
 
-    ParsedConfig* GetGlobalParsedObject(size_t index) const {
-      return service_config_->GetParsedGlobalServiceConfigObject(index);
+    ParsedConfig* GetGlobalParsedConfig(size_t index) const {
+      return service_config_->GetGlobalParsedConfig(index);
     }
 
    private:
     RefCountedPtr<ServiceConfig> service_config_;
-    const ServiceConfigObjectsVector* method_params_vector_ = nullptr;
+    const ParsedConfigVector* method_params_vector_ = nullptr;
   };
 
   /// Creates a new service config from parsing \a json_string.
@@ -132,25 +132,24 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
 
   const char* service_config_json() const { return service_config_json_.get(); }
 
-  /// Retrieves the parsed global service config object at index \a index. The
+  /// Retrieves the global parsed config at index \a index. The
   /// lifetime of the returned object is tied to the lifetime of the
   /// ServiceConfig object.
-  ParsedConfig* GetParsedGlobalServiceConfigObject(size_t index) {
-    GPR_DEBUG_ASSERT(index < parsed_global_service_config_objects_.size());
-    return parsed_global_service_config_objects_[index].get();
+  ParsedConfig* GetGlobalParsedConfig(size_t index) {
+    GPR_DEBUG_ASSERT(index < parsed_global_configs_.size());
+    return parsed_global_configs_[index].get();
   }
 
-  /// Retrieves the vector of method service config objects for a given path \a
-  /// path. The lifetime of the returned vector and contained objects is tied to
-  /// the lifetime of the ServiceConfig object.
-  const ServiceConfigObjectsVector* GetMethodServiceConfigObjectsVector(
-      const grpc_slice& path);
+  /// Retrieves the vector of parsed configs for the method identified
+  /// by \a path.  The lifetime of the returned vector and contained objects
+  /// is tied to the lifetime of the ServiceConfig object.
+  const ParsedConfigVector* GetMethodParsedConfigVector(const grpc_slice& path);
 
   /// Globally register a service config parser. On successful registration, it
   /// returns the index at which the parser was registered. On failure, -1 is
   /// returned. Each new service config update will go through all the
   /// registered parser. Each parser is responsible for reading the service
-  /// config json and returning a parsed object. This parsed object can later be
+  /// config json and returning a parsed config. This parsed config can later be
   /// retrieved using the same index that was returned at registration time.
   static size_t RegisterParser(UniquePtr<Parser> parser);
 
@@ -180,26 +179,25 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
   static UniquePtr<char> ParseJsonMethodName(grpc_json* json,
                                              grpc_error** error);
 
-  grpc_error* ParseJsonMethodConfigToServiceConfigObjectsTable(
+  grpc_error* ParseJsonMethodConfigToServiceConfigVectorTable(
       const grpc_json* json,
-      SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries,
-      size_t* idx);
+      SliceHashTable<const ParsedConfigVector*>::Entry* entries, size_t* idx);
 
   UniquePtr<char> service_config_json_;
   UniquePtr<char> json_string_;  // Underlying storage for json_tree.
   grpc_json* json_tree_;
 
   InlinedVector<UniquePtr<ParsedConfig>, kNumPreallocatedParsers>
-      parsed_global_service_config_objects_;
-  // A map from the method name to the service config objects vector. Note that
-  // we are using a raw pointer and not a unique pointer so that we can use the
-  // same vector for multiple names.
-  RefCountedPtr<SliceHashTable<const ServiceConfigObjectsVector*>>
-      parsed_method_service_config_objects_table_;
+      parsed_global_configs_;
+  // A map from the method name to the parsed config vector. Note that we are
+  // using a raw pointer and not a unique pointer so that we can use the same
+  // vector for multiple names.
+  RefCountedPtr<SliceHashTable<const ParsedConfigVector*>>
+      parsed_method_configs_table_;
   // Storage for all the vectors that are being used in
-  // parsed_method_service_config_objects_table_.
-  InlinedVector<UniquePtr<ServiceConfigObjectsVector>, 32>
-      service_config_objects_vectors_storage_;
+  // parsed_method_configs_table_.
+  InlinedVector<UniquePtr<ParsedConfigVector>, 32>
+      parsed_method_config_vectors_storage_;
 };
 
 }  // namespace grpc_core
index a284e69..dd16ede 100644 (file)
@@ -75,6 +75,9 @@
 
 namespace grpc_core {
 
+TraceFlag grpc_trace_subchannel(false, "subchannel");
+DebugOnlyTraceFlag grpc_trace_subchannel_refcount(false, "subchannel_refcount");
+
 //
 // ConnectedSubchannel
 //
@@ -83,7 +86,7 @@ ConnectedSubchannel::ConnectedSubchannel(
     grpc_channel_stack* channel_stack, const grpc_channel_args* args,
     RefCountedPtr<channelz::SubchannelNode> channelz_subchannel,
     intptr_t socket_uuid)
-    : RefCounted<ConnectedSubchannel>(&grpc_trace_stream_refcount),
+    : ConnectedSubchannelInterface(&grpc_trace_subchannel_refcount),
       channel_stack_(channel_stack),
       args_(grpc_channel_args_copy(args)),
       channelz_subchannel_(std::move(channelz_subchannel)),
@@ -303,8 +306,7 @@ void SubchannelCall::IncrementRefCount(const grpc_core::DebugLocation& location,
 // Subchannel::ConnectedSubchannelStateWatcher
 //
 
-class Subchannel::ConnectedSubchannelStateWatcher
-    : public InternallyRefCounted<ConnectedSubchannelStateWatcher> {
+class Subchannel::ConnectedSubchannelStateWatcher {
  public:
   // Must be instantiated while holding c->mu.
   explicit ConnectedSubchannelStateWatcher(Subchannel* c) : subchannel_(c) {
@@ -312,38 +314,17 @@ class Subchannel::ConnectedSubchannelStateWatcher
     GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "state_watcher");
     GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "connecting");
     // Start watching for connectivity state changes.
-    // Callback uses initial ref to this.
     GRPC_CLOSURE_INIT(&on_connectivity_changed_, OnConnectivityChanged, this,
                       grpc_schedule_on_exec_ctx);
     c->connected_subchannel_->NotifyOnStateChange(c->pollset_set_,
                                                   &pending_connectivity_state_,
                                                   &on_connectivity_changed_);
-    // Start health check if needed.
-    grpc_connectivity_state health_state = GRPC_CHANNEL_READY;
-    if (c->health_check_service_name_ != nullptr) {
-      health_check_client_ = MakeOrphanable<HealthCheckClient>(
-          c->health_check_service_name_.get(), c->connected_subchannel_,
-          c->pollset_set_, c->channelz_node_);
-      GRPC_CLOSURE_INIT(&on_health_changed_, OnHealthChanged, this,
-                        grpc_schedule_on_exec_ctx);
-      Ref().release();  // Ref for health callback tracked manually.
-      health_check_client_->NotifyOnHealthChange(&health_state_,
-                                                 &on_health_changed_);
-      health_state = GRPC_CHANNEL_CONNECTING;
-    }
-    // Report initial state.
-    c->SetConnectivityStateLocked(GRPC_CHANNEL_READY, "subchannel_connected");
-    grpc_connectivity_state_set(&c->state_and_health_tracker_, health_state,
-                                "subchannel_connected");
   }
 
   ~ConnectedSubchannelStateWatcher() {
     GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "state_watcher");
   }
 
-  // Must be called while holding subchannel_->mu.
-  void Orphan() override { health_check_client_.reset(); }
-
  private:
   static void OnConnectivityChanged(void* arg, grpc_error* error) {
     auto* self = static_cast<ConnectedSubchannelStateWatcher*>(arg);
@@ -354,7 +335,7 @@ class Subchannel::ConnectedSubchannelStateWatcher
         case GRPC_CHANNEL_TRANSIENT_FAILURE:
         case GRPC_CHANNEL_SHUTDOWN: {
           if (!c->disconnected_ && c->connected_subchannel_ != nullptr) {
-            if (grpc_trace_stream_refcount.enabled()) {
+            if (grpc_trace_subchannel.enabled()) {
               gpr_log(GPR_INFO,
                       "Connected subchannel %p of subchannel %p has gone into "
                       "%s. Attempting to reconnect.",
@@ -363,20 +344,10 @@ class Subchannel::ConnectedSubchannelStateWatcher
                           self->pending_connectivity_state_));
             }
             c->connected_subchannel_.reset();
-            c->connected_subchannel_watcher_.reset();
-            self->last_connectivity_state_ = GRPC_CHANNEL_TRANSIENT_FAILURE;
-            c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                          "reflect_child");
-            grpc_connectivity_state_set(&c->state_and_health_tracker_,
-                                        GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                        "reflect_child");
+            c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE);
             c->backoff_begun_ = false;
             c->backoff_.Reset();
-            c->MaybeStartConnectingLocked();
-          } else {
-            self->last_connectivity_state_ = GRPC_CHANNEL_SHUTDOWN;
           }
-          self->health_check_client_.reset();
           break;
         }
         default: {
@@ -384,96 +355,230 @@ class Subchannel::ConnectedSubchannelStateWatcher
           // a callback for READY, because that was the state we started
           // this watch from.  And a connected subchannel should never go
           // from READY to CONNECTING or IDLE.
-          self->last_connectivity_state_ = self->pending_connectivity_state_;
-          c->SetConnectivityStateLocked(self->pending_connectivity_state_,
-                                        "reflect_child");
-          if (self->pending_connectivity_state_ != GRPC_CHANNEL_READY) {
-            grpc_connectivity_state_set(&c->state_and_health_tracker_,
-                                        self->pending_connectivity_state_,
-                                        "reflect_child");
-          }
+          c->SetConnectivityStateLocked(self->pending_connectivity_state_);
           c->connected_subchannel_->NotifyOnStateChange(
               nullptr, &self->pending_connectivity_state_,
               &self->on_connectivity_changed_);
-          self = nullptr;  // So we don't unref below.
+          return;  // So we don't delete ourself below.
         }
       }
     }
-    // Don't unref until we've released the lock, because this might
+    // Don't delete until we've released the lock, because this might
     // cause the subchannel (which contains the lock) to be destroyed.
-    if (self != nullptr) self->Unref();
+    Delete(self);
+  }
+
+  Subchannel* subchannel_;
+  grpc_closure on_connectivity_changed_;
+  grpc_connectivity_state pending_connectivity_state_ = GRPC_CHANNEL_READY;
+};
+
+//
+// Subchannel::ConnectivityStateWatcherList
+//
+
+void Subchannel::ConnectivityStateWatcherList::AddWatcherLocked(
+    UniquePtr<ConnectivityStateWatcher> watcher) {
+  watchers_.insert(MakePair(watcher.get(), std::move(watcher)));
+}
+
+void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked(
+    ConnectivityStateWatcher* watcher) {
+  watchers_.erase(watcher);
+}
+
+void Subchannel::ConnectivityStateWatcherList::NotifyLocked(
+    Subchannel* subchannel, grpc_connectivity_state state) {
+  for (const auto& p : watchers_) {
+    RefCountedPtr<ConnectedSubchannel> connected_subchannel;
+    if (state == GRPC_CHANNEL_READY) {
+      connected_subchannel = subchannel->connected_subchannel_;
+    }
+    // TODO(roth): In principle, it seems wrong to send this notification
+    // to the watcher while holding the subchannel's mutex, since it could
+    // lead to a deadlock if the watcher calls back into the subchannel
+    // before returning back to us.  In practice, this doesn't happen,
+    // because the LB policy code that watches subchannels always bounces
+    // the notification into the client_channel control-plane combiner
+    // before processing it.  But if we ever have any other callers here,
+    // we will probably need to change this.
+    p.second->OnConnectivityStateChange(state, std::move(connected_subchannel));
+  }
+}
+
+//
+// Subchannel::HealthWatcherMap::HealthWatcher
+//
+
+// State needed for tracking the connectivity state with a particular
+// health check service name.
+class Subchannel::HealthWatcherMap::HealthWatcher
+    : public InternallyRefCounted<HealthWatcher> {
+ public:
+  HealthWatcher(Subchannel* c, UniquePtr<char> health_check_service_name,
+                grpc_connectivity_state subchannel_state)
+      : subchannel_(c),
+        health_check_service_name_(std::move(health_check_service_name)),
+        state_(subchannel_state == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING
+                                                      : subchannel_state) {
+    GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "health_watcher");
+    GRPC_CLOSURE_INIT(&on_health_changed_, OnHealthChanged, this,
+                      grpc_schedule_on_exec_ctx);
+    // If the subchannel is already connected, start health checking.
+    if (subchannel_state == GRPC_CHANNEL_READY) StartHealthCheckingLocked();
+  }
+
+  ~HealthWatcher() {
+    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "health_watcher");
+  }
+
+  const char* health_check_service_name() const {
+    return health_check_service_name_.get();
+  }
+
+  grpc_connectivity_state state() const { return state_; }
+
+  void AddWatcherLocked(grpc_connectivity_state initial_state,
+                        UniquePtr<ConnectivityStateWatcher> watcher) {
+    if (state_ != initial_state) {
+      RefCountedPtr<ConnectedSubchannel> connected_subchannel;
+      if (state_ == GRPC_CHANNEL_READY) {
+        connected_subchannel = subchannel_->connected_subchannel_;
+      }
+      watcher->OnConnectivityStateChange(state_,
+                                         std::move(connected_subchannel));
+    }
+    watcher_list_.AddWatcherLocked(std::move(watcher));
+  }
+
+  void RemoveWatcherLocked(ConnectivityStateWatcher* watcher) {
+    watcher_list_.RemoveWatcherLocked(watcher);
+  }
+
+  bool HasWatchers() const { return !watcher_list_.empty(); }
+
+  void NotifyLocked(grpc_connectivity_state state) {
+    if (state == GRPC_CHANNEL_READY) {
+      // If we had not already notified for CONNECTING state, do so now.
+      // (We may have missed this earlier, because if the transition
+      // from IDLE to CONNECTING to READY was too quick, the connected
+      // subchannel may not have sent us a notification for CONNECTING.)
+      if (state_ != GRPC_CHANNEL_CONNECTING) {
+        state_ = GRPC_CHANNEL_CONNECTING;
+        watcher_list_.NotifyLocked(subchannel_, state_);
+      }
+      // If we've become connected, start health checking.
+      StartHealthCheckingLocked();
+    } else {
+      state_ = state;
+      watcher_list_.NotifyLocked(subchannel_, state_);
+      // We're not connected, so stop health checking.
+      health_check_client_.reset();
+    }
+  }
+
+  void Orphan() override {
+    watcher_list_.Clear();
+    health_check_client_.reset();
+    Unref();
+  }
+
+ private:
+  void StartHealthCheckingLocked() {
+    GPR_ASSERT(health_check_client_ == nullptr);
+    health_check_client_ = MakeOrphanable<HealthCheckClient>(
+        health_check_service_name_.get(), subchannel_->connected_subchannel_,
+        subchannel_->pollset_set_, subchannel_->channelz_node_);
+    Ref().release();  // Ref for health callback tracked manually.
+    health_check_client_->NotifyOnHealthChange(&state_, &on_health_changed_);
   }
 
   static void OnHealthChanged(void* arg, grpc_error* error) {
-    auto* self = static_cast<ConnectedSubchannelStateWatcher*>(arg);
+    auto* self = static_cast<HealthWatcher*>(arg);
     Subchannel* c = self->subchannel_;
     {
       MutexLock lock(&c->mu_);
-      if (self->health_state_ != GRPC_CHANNEL_SHUTDOWN &&
+      if (self->state_ != GRPC_CHANNEL_SHUTDOWN &&
           self->health_check_client_ != nullptr) {
-        if (self->last_connectivity_state_ == GRPC_CHANNEL_READY) {
-          grpc_connectivity_state_set(&c->state_and_health_tracker_,
-                                      self->health_state_, "health_changed");
-        }
+        self->watcher_list_.NotifyLocked(c, self->state_);
+        // Renew watch.
         self->health_check_client_->NotifyOnHealthChange(
-            &self->health_state_, &self->on_health_changed_);
-        self = nullptr;  // So we don't unref below.
+            &self->state_, &self->on_health_changed_);
+        return;  // So we don't unref below.
       }
     }
     // Don't unref until we've released the lock, because this might
     // cause the subchannel (which contains the lock) to be destroyed.
-    if (self != nullptr) self->Unref();
+    self->Unref();
   }
 
   Subchannel* subchannel_;
-  grpc_closure on_connectivity_changed_;
-  grpc_connectivity_state pending_connectivity_state_ = GRPC_CHANNEL_READY;
-  grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_READY;
+  UniquePtr<char> health_check_service_name_;
   OrphanablePtr<HealthCheckClient> health_check_client_;
   grpc_closure on_health_changed_;
-  grpc_connectivity_state health_state_ = GRPC_CHANNEL_CONNECTING;
+  grpc_connectivity_state state_;
+  ConnectivityStateWatcherList watcher_list_;
 };
 
 //
-// Subchannel::ExternalStateWatcher
+// Subchannel::HealthWatcherMap
 //
 
-struct Subchannel::ExternalStateWatcher {
-  ExternalStateWatcher(Subchannel* subchannel, grpc_pollset_set* pollset_set,
-                       grpc_closure* notify)
-      : subchannel(subchannel), pollset_set(pollset_set), notify(notify) {
-    GRPC_SUBCHANNEL_WEAK_REF(subchannel, "external_state_watcher+init");
-    GRPC_CLOSURE_INIT(&on_state_changed, OnStateChanged, this,
-                      grpc_schedule_on_exec_ctx);
+void Subchannel::HealthWatcherMap::AddWatcherLocked(
+    Subchannel* subchannel, grpc_connectivity_state initial_state,
+    UniquePtr<char> health_check_service_name,
+    UniquePtr<ConnectivityStateWatcher> watcher) {
+  // If the health check service name is not already present in the map,
+  // add it.
+  auto it = map_.find(health_check_service_name.get());
+  HealthWatcher* health_watcher;
+  if (it == map_.end()) {
+    const char* key = health_check_service_name.get();
+    auto w = MakeOrphanable<HealthWatcher>(
+        subchannel, std::move(health_check_service_name), subchannel->state_);
+    health_watcher = w.get();
+    map_[key] = std::move(w);
+  } else {
+    health_watcher = it->second.get();
   }
+  // Add the watcher to the entry.
+  health_watcher->AddWatcherLocked(initial_state, std::move(watcher));
+}
 
-  static void OnStateChanged(void* arg, grpc_error* error) {
-    ExternalStateWatcher* w = static_cast<ExternalStateWatcher*>(arg);
-    grpc_closure* follow_up = w->notify;
-    if (w->pollset_set != nullptr) {
-      grpc_pollset_set_del_pollset_set(w->subchannel->pollset_set_,
-                                       w->pollset_set);
-    }
-    {
-      MutexLock lock(&w->subchannel->mu_);
-      if (w->subchannel->external_state_watcher_list_ == w) {
-        w->subchannel->external_state_watcher_list_ = w->next;
-      }
-      if (w->next != nullptr) w->next->prev = w->prev;
-      if (w->prev != nullptr) w->prev->next = w->next;
-    }
-    GRPC_SUBCHANNEL_WEAK_UNREF(w->subchannel, "external_state_watcher+done");
-    Delete(w);
-    GRPC_CLOSURE_SCHED(follow_up, GRPC_ERROR_REF(error));
+void Subchannel::HealthWatcherMap::RemoveWatcherLocked(
+    const char* health_check_service_name, ConnectivityStateWatcher* watcher) {
+  auto it = map_.find(health_check_service_name);
+  GPR_ASSERT(it != map_.end());
+  it->second->RemoveWatcherLocked(watcher);
+  // If we just removed the last watcher for this service name, remove
+  // the map entry.
+  if (!it->second->HasWatchers()) map_.erase(it);
+}
+
+void Subchannel::HealthWatcherMap::NotifyLocked(grpc_connectivity_state state) {
+  for (const auto& p : map_) {
+    p.second->NotifyLocked(state);
   }
+}
 
-  Subchannel* subchannel;
-  grpc_pollset_set* pollset_set;
-  grpc_closure* notify;
-  grpc_closure on_state_changed;
-  ExternalStateWatcher* next = nullptr;
-  ExternalStateWatcher* prev = nullptr;
-};
+grpc_connectivity_state
+Subchannel::HealthWatcherMap::CheckConnectivityStateLocked(
+    Subchannel* subchannel, const char* health_check_service_name) {
+  auto it = map_.find(health_check_service_name);
+  if (it == map_.end()) {
+    // If the health check service name is not found in the map, we're
+    // not currently doing a health check for that service name.  If the
+    // subchannel's state without health checking is READY, report
+    // CONNECTING, since that's what we'd be in as soon as we do start a
+    // watch.  Otherwise, report the channel's state without health checking.
+    return subchannel->state_ == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING
+                                                    : subchannel->state_;
+  }
+  HealthWatcher* health_watcher = it->second.get();
+  return health_watcher->state();
+}
+
+void Subchannel::HealthWatcherMap::ShutdownLocked() { map_.clear(); }
 
 //
 // Subchannel
@@ -560,13 +665,6 @@ Subchannel::Subchannel(SubchannelKey* key, grpc_connector* connector,
   if (new_args != nullptr) grpc_channel_args_destroy(new_args);
   GRPC_CLOSURE_INIT(&on_connecting_finished_, OnConnectingFinished, this,
                     grpc_schedule_on_exec_ctx);
-  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
-                               "subchannel");
-  grpc_connectivity_state_init(&state_and_health_tracker_, GRPC_CHANNEL_IDLE,
-                               "subchannel");
-  health_check_service_name_ =
-      UniquePtr<char>(gpr_strdup(grpc_channel_arg_get_string(
-          grpc_channel_args_find(args_, "grpc.temp.health_check"))));
   const grpc_arg* arg = grpc_channel_args_find(args_, GRPC_ARG_ENABLE_CHANNELZ);
   const bool channelz_enabled =
       grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT);
@@ -593,8 +691,6 @@ Subchannel::~Subchannel() {
     channelz_node_->MarkSubchannelDestroyed();
   }
   grpc_channel_args_destroy(args_);
-  grpc_connectivity_state_destroy(&state_tracker_);
-  grpc_connectivity_state_destroy(&state_and_health_tracker_);
   grpc_connector_unref(connector_);
   grpc_pollset_set_destroy(pollset_set_);
   Delete(key_);
@@ -698,55 +794,67 @@ const char* Subchannel::GetTargetAddress() {
   return addr_str;
 }
 
-RefCountedPtr<ConnectedSubchannel> Subchannel::connected_subchannel() {
-  MutexLock lock(&mu_);
-  return connected_subchannel_;
-}
-
 channelz::SubchannelNode* Subchannel::channelz_node() {
   return channelz_node_.get();
 }
 
-grpc_connectivity_state Subchannel::CheckConnectivity(
-    bool inhibit_health_checking) {
-  grpc_connectivity_state_tracker* tracker =
-      inhibit_health_checking ? &state_tracker_ : &state_and_health_tracker_;
-  grpc_connectivity_state state = grpc_connectivity_state_check(tracker);
+grpc_connectivity_state Subchannel::CheckConnectivityState(
+    const char* health_check_service_name,
+    RefCountedPtr<ConnectedSubchannel>* connected_subchannel) {
+  MutexLock lock(&mu_);
+  grpc_connectivity_state state;
+  if (health_check_service_name == nullptr) {
+    state = state_;
+  } else {
+    state = health_watcher_map_.CheckConnectivityStateLocked(
+        this, health_check_service_name);
+  }
+  if (connected_subchannel != nullptr && state == GRPC_CHANNEL_READY) {
+    *connected_subchannel = connected_subchannel_;
+  }
   return state;
 }
 
-void Subchannel::NotifyOnStateChange(grpc_pollset_set* interested_parties,
-                                     grpc_connectivity_state* state,
-                                     grpc_closure* notify,
-                                     bool inhibit_health_checking) {
-  grpc_connectivity_state_tracker* tracker =
-      inhibit_health_checking ? &state_tracker_ : &state_and_health_tracker_;
-  ExternalStateWatcher* w;
-  if (state == nullptr) {
-    MutexLock lock(&mu_);
-    for (w = external_state_watcher_list_; w != nullptr; w = w->next) {
-      if (w->notify == notify) {
-        grpc_connectivity_state_notify_on_state_change(tracker, nullptr,
-                                                       &w->on_state_changed);
-      }
+void Subchannel::WatchConnectivityState(
+    grpc_connectivity_state initial_state,
+    UniquePtr<char> health_check_service_name,
+    UniquePtr<ConnectivityStateWatcher> watcher) {
+  MutexLock lock(&mu_);
+  grpc_pollset_set* interested_parties = watcher->interested_parties();
+  if (interested_parties != nullptr) {
+    grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties);
+  }
+  if (health_check_service_name == nullptr) {
+    if (state_ != initial_state) {
+      watcher->OnConnectivityStateChange(state_, connected_subchannel_);
     }
+    watcher_list_.AddWatcherLocked(std::move(watcher));
   } else {
-    w = New<ExternalStateWatcher>(this, interested_parties, notify);
-    if (interested_parties != nullptr) {
-      grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties);
-    }
-    MutexLock lock(&mu_);
-    if (external_state_watcher_list_ != nullptr) {
-      w->next = external_state_watcher_list_;
-      w->next->prev = w;
-    }
-    external_state_watcher_list_ = w;
-    grpc_connectivity_state_notify_on_state_change(tracker, state,
-                                                   &w->on_state_changed);
-    MaybeStartConnectingLocked();
+    health_watcher_map_.AddWatcherLocked(this, initial_state,
+                                         std::move(health_check_service_name),
+                                         std::move(watcher));
   }
 }
 
+void Subchannel::CancelConnectivityStateWatch(
+    const char* health_check_service_name, ConnectivityStateWatcher* watcher) {
+  MutexLock lock(&mu_);
+  grpc_pollset_set* interested_parties = watcher->interested_parties();
+  if (interested_parties != nullptr) {
+    grpc_pollset_set_del_pollset_set(pollset_set_, interested_parties);
+  }
+  if (health_check_service_name == nullptr) {
+    watcher_list_.RemoveWatcherLocked(watcher);
+  } else {
+    health_watcher_map_.RemoveWatcherLocked(health_check_service_name, watcher);
+  }
+}
+
+void Subchannel::AttemptToConnect() {
+  MutexLock lock(&mu_);
+  MaybeStartConnectingLocked();
+}
+
 void Subchannel::ResetBackoff() {
   MutexLock lock(&mu_);
   backoff_.Reset();
@@ -818,15 +926,19 @@ const char* SubchannelConnectivityStateChangeString(
 
 }  // namespace
 
-void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state,
-                                            const char* reason) {
+// Note: Must be called with a state that is different from the current state.
+void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state) {
+  state_ = state;
   if (channelz_node_ != nullptr) {
     channelz_node_->AddTraceEvent(
         channelz::ChannelTrace::Severity::Info,
         grpc_slice_from_static_string(
             SubchannelConnectivityStateChangeString(state)));
   }
-  grpc_connectivity_state_set(&state_tracker_, state, reason);
+  // Notify non-health watchers.
+  watcher_list_.NotifyLocked(this, state);
+  // Notify health watchers.
+  health_watcher_map_.NotifyLocked(state);
 }
 
 void Subchannel::MaybeStartConnectingLocked() {
@@ -842,11 +954,6 @@ void Subchannel::MaybeStartConnectingLocked() {
     // Already connected: don't restart.
     return;
   }
-  if (!grpc_connectivity_state_has_watchers(&state_tracker_) &&
-      !grpc_connectivity_state_has_watchers(&state_and_health_tracker_)) {
-    // Nobody is interested in connecting: so don't just yet.
-    return;
-  }
   connecting_ = true;
   GRPC_SUBCHANNEL_WEAK_REF(this, "connecting");
   if (!backoff_begun_) {
@@ -903,9 +1010,7 @@ void Subchannel::ContinueConnectingLocked() {
   next_attempt_deadline_ = backoff_.NextAttemptTime();
   args.deadline = std::max(next_attempt_deadline_, min_deadline);
   args.channel_args = args_;
-  SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING, "connecting");
-  grpc_connectivity_state_set(&state_and_health_tracker_,
-                              GRPC_CHANNEL_CONNECTING, "connecting");
+  SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING);
   grpc_connector_connect(connector_, &args, &connecting_result_,
                          &on_connecting_finished_);
 }
@@ -924,12 +1029,7 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
       GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
     } else {
       gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error));
-      c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                    "connect_failed");
-      grpc_connectivity_state_set(&c->state_and_health_tracker_,
-                                  GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                  "connect_failed");
-      c->MaybeStartConnectingLocked();
+      c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE);
       GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
     }
   }
@@ -982,8 +1082,9 @@ bool Subchannel::PublishTransportLocked() {
   gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p",
           connected_subchannel_.get(), this);
   // Instantiate state watcher.  Will clean itself up.
-  connected_subchannel_watcher_ =
-      MakeOrphanable<ConnectedSubchannelStateWatcher>(this);
+  New<ConnectedSubchannelStateWatcher>(this);
+  // Report initial state.
+  SetConnectivityStateLocked(GRPC_CHANNEL_READY);
   return true;
 }
 
@@ -1000,7 +1101,7 @@ void Subchannel::Disconnect() {
   grpc_connector_shutdown(connector_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                           "Subchannel disconnected"));
   connected_subchannel_.reset();
-  connected_subchannel_watcher_.reset();
+  health_watcher_map_.ShutdownLocked();
 }
 
 gpr_atm Subchannel::RefMutate(
@@ -1008,7 +1109,7 @@ gpr_atm Subchannel::RefMutate(
   gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&ref_pair_, delta)
                             : gpr_atm_no_barrier_fetch_add(&ref_pair_, delta);
 #ifndef NDEBUG
-  if (grpc_trace_stream_refcount.enabled()) {
+  if (grpc_trace_subchannel_refcount.enabled()) {
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", this,
             purpose, old_val, old_val + delta, reason);
index e3efc89..2f05792 100644 (file)
 
 #include "src/core/ext/filters/client_channel/client_channel_channelz.h"
 #include "src/core/ext/filters/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/subchannel_interface.h"
 #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gprpp/arena.h"
+#include "src/core/lib/gprpp/map.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
@@ -68,7 +70,7 @@ namespace grpc_core {
 
 class SubchannelCall;
 
-class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
+class ConnectedSubchannel : public ConnectedSubchannelInterface {
  public:
   struct CallArgs {
     grpc_polling_entity* pollent;
@@ -77,7 +79,7 @@ class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
     grpc_millis deadline;
     Arena* arena;
     grpc_call_context_element* context;
-    grpc_core::CallCombiner* call_combiner;
+    CallCombiner* call_combiner;
     size_t parent_data_size;
   };
 
@@ -95,7 +97,7 @@ class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
                                            grpc_error** error);
 
   grpc_channel_stack* channel_stack() const { return channel_stack_; }
-  const grpc_channel_args* args() const { return args_; }
+  const grpc_channel_args* args() const override { return args_; }
   channelz::SubchannelNode* channelz_subchannel() const {
     return channelz_subchannel_.get();
   }
@@ -176,6 +178,9 @@ class SubchannelCall {
 // provides a target for load balancing.
 class Subchannel {
  public:
+  typedef SubchannelInterface::ConnectivityStateWatcher
+      ConnectivityStateWatcher;
+
   // The ctor and dtor are not intended to use directly.
   Subchannel(SubchannelKey* key, grpc_connector* connector,
              const grpc_channel_args* args);
@@ -201,20 +206,36 @@ class Subchannel {
   // Caller doesn't take ownership.
   const char* GetTargetAddress();
 
-  // Gets the connected subchannel - or nullptr if not connected (which may
-  // happen before it initially connects or during transient failures).
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel();
-
   channelz::SubchannelNode* channelz_node();
 
-  // Polls the current connectivity state of the subchannel.
-  grpc_connectivity_state CheckConnectivity(bool inhibit_health_checking);
-
-  // When the connectivity state of the subchannel changes from \a *state,
-  // invokes \a notify and updates \a *state with the new state.
-  void NotifyOnStateChange(grpc_pollset_set* interested_parties,
-                           grpc_connectivity_state* state, grpc_closure* notify,
-                           bool inhibit_health_checking);
+  // Returns the current connectivity state of the subchannel.
+  // If health_check_service_name is non-null, the returned connectivity
+  // state will be based on the state reported by the backend for that
+  // service name.
+  // If the return value is GRPC_CHANNEL_READY, also sets *connected_subchannel.
+  grpc_connectivity_state CheckConnectivityState(
+      const char* health_check_service_name,
+      RefCountedPtr<ConnectedSubchannel>* connected_subchannel);
+
+  // Starts watching the subchannel's connectivity state.
+  // The first callback to the watcher will be delivered when the
+  // subchannel's connectivity state becomes a value other than
+  // initial_state, which may happen immediately.
+  // Subsequent callbacks will be delivered as the subchannel's state
+  // changes.
+  // The watcher will be destroyed either when the subchannel is
+  // destroyed or when CancelConnectivityStateWatch() is called.
+  void WatchConnectivityState(grpc_connectivity_state initial_state,
+                              UniquePtr<char> health_check_service_name,
+                              UniquePtr<ConnectivityStateWatcher> watcher);
+
+  // Cancels a connectivity state watch.
+  // If the watcher has already been destroyed, this is a no-op.
+  void CancelConnectivityStateWatch(const char* health_check_service_name,
+                                    ConnectivityStateWatcher* watcher);
+
+  // Attempt to connect to the backend.  Has no effect if already connected.
+  void AttemptToConnect();
 
   // Resets the connection backoff of the subchannel.
   // TODO(roth): Move connection backoff out of subchannels and up into LB
@@ -236,12 +257,65 @@ class Subchannel {
                                                  grpc_resolved_address* addr);
 
  private:
-  struct ExternalStateWatcher;
+  // A linked list of ConnectivityStateWatchers that are monitoring the
+  // subchannel's state.
+  class ConnectivityStateWatcherList {
+   public:
+    ~ConnectivityStateWatcherList() { Clear(); }
+
+    void AddWatcherLocked(UniquePtr<ConnectivityStateWatcher> watcher);
+    void RemoveWatcherLocked(ConnectivityStateWatcher* watcher);
+
+    // Notifies all watchers in the list about a change to state.
+    void NotifyLocked(Subchannel* subchannel, grpc_connectivity_state state);
+
+    void Clear() { watchers_.clear(); }
+
+    bool empty() const { return watchers_.empty(); }
+
+   private:
+    // TODO(roth): This could be a set instead of a map if we had a set
+    // implementation.
+    Map<ConnectivityStateWatcher*, UniquePtr<ConnectivityStateWatcher>>
+        watchers_;
+  };
+
+  // A map that tracks ConnectivityStateWatchers using a particular health
+  // check service name.
+  //
+  // There is one entry in the map for each health check service name.
+  // Entries exist only as long as there are watchers using the
+  // corresponding service name.
+  //
+  // A health check client is maintained only while the subchannel is in
+  // state READY.
+  class HealthWatcherMap {
+   public:
+    void AddWatcherLocked(Subchannel* subchannel,
+                          grpc_connectivity_state initial_state,
+                          UniquePtr<char> health_check_service_name,
+                          UniquePtr<ConnectivityStateWatcher> watcher);
+    void RemoveWatcherLocked(const char* health_check_service_name,
+                             ConnectivityStateWatcher* watcher);
+
+    // Notifies the watcher when the subchannel's state changes.
+    void NotifyLocked(grpc_connectivity_state state);
+
+    grpc_connectivity_state CheckConnectivityStateLocked(
+        Subchannel* subchannel, const char* health_check_service_name);
+
+    void ShutdownLocked();
+
+   private:
+    class HealthWatcher;
+
+    Map<const char*, OrphanablePtr<HealthWatcher>, StringLess> map_;
+  };
+
   class ConnectedSubchannelStateWatcher;
 
   // Sets the subchannel's connectivity state to \a state.
-  void SetConnectivityStateLocked(grpc_connectivity_state state,
-                                  const char* reason);
+  void SetConnectivityStateLocked(grpc_connectivity_state state);
 
   // Methods for connection.
   void MaybeStartConnectingLocked();
@@ -279,15 +353,15 @@ class Subchannel {
   grpc_closure on_connecting_finished_;
   // Active connection, or null.
   RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-  OrphanablePtr<ConnectedSubchannelStateWatcher> connected_subchannel_watcher_;
   bool connecting_ = false;
   bool disconnected_ = false;
 
   // Connectivity state tracking.
-  grpc_connectivity_state_tracker state_tracker_;
-  grpc_connectivity_state_tracker state_and_health_tracker_;
-  UniquePtr<char> health_check_service_name_;
-  ExternalStateWatcher* external_state_watcher_list_ = nullptr;
+  grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE;
+  // The list of watchers without a health check service name.
+  ConnectivityStateWatcherList watcher_list_;
+  // The map of watchers with health check service names.
+  HealthWatcherMap health_watcher_map_;
 
   // Backoff state.
   BackOff backoff_;
diff --git a/src/core/ext/filters/client_channel/subchannel_interface.h b/src/core/ext/filters/client_channel/subchannel_interface.h
new file mode 100644 (file)
index 0000000..10b1bf1
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *
+ * Copyright 2019 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_SUBCHANNEL_INTERFACE_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+
+namespace grpc_core {
+
+// TODO(roth): In a subsequent PR, remove this from this API.
+class ConnectedSubchannelInterface
+    : public RefCounted<ConnectedSubchannelInterface> {
+ public:
+  virtual const grpc_channel_args* args() const GRPC_ABSTRACT;
+
+ protected:
+  template <typename TraceFlagT = TraceFlag>
+  explicit ConnectedSubchannelInterface(TraceFlagT* trace_flag = nullptr)
+      : RefCounted<ConnectedSubchannelInterface>(trace_flag) {}
+};
+
+class SubchannelInterface : public RefCounted<SubchannelInterface> {
+ public:
+  class ConnectivityStateWatcher {
+   public:
+    virtual ~ConnectivityStateWatcher() = default;
+
+    // Will be invoked whenever the subchannel's connectivity state
+    // changes.  There will be only one invocation of this method on a
+    // given watcher instance at any given time.
+    //
+    // When the state changes to READY, connected_subchannel will
+    // contain a ref to the connected subchannel.  When it changes from
+    // READY to some other state, the implementation must release its
+    // ref to the connected subchannel.
+    virtual void OnConnectivityStateChange(
+        grpc_connectivity_state new_state,
+        RefCountedPtr<ConnectedSubchannelInterface>
+            connected_subchannel)  // NOLINT
+        GRPC_ABSTRACT;
+
+    // TODO(roth): Remove this as soon as we move to EventManager-based
+    // polling.
+    virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT;
+
+    GRPC_ABSTRACT_BASE_CLASS
+  };
+
+  virtual ~SubchannelInterface() = default;
+
+  // Returns the current connectivity state of the subchannel.
+  virtual grpc_connectivity_state CheckConnectivityState(
+      RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
+      GRPC_ABSTRACT;
+
+  // Starts watching the subchannel's connectivity state.
+  // The first callback to the watcher will be delivered when the
+  // subchannel's connectivity state becomes a value other than
+  // initial_state, which may happen immediately.
+  // Subsequent callbacks will be delivered as the subchannel's state
+  // changes.
+  // The watcher will be destroyed either when the subchannel is
+  // destroyed or when CancelConnectivityStateWatch() is called.
+  // There can be only one watcher of a given subchannel.  It is not
+  // valid to call this method a second time without first cancelling
+  // the previous watcher using CancelConnectivityStateWatch().
+  virtual void WatchConnectivityState(
+      grpc_connectivity_state initial_state,
+      UniquePtr<ConnectivityStateWatcher> watcher) GRPC_ABSTRACT;
+
+  // Cancels a connectivity state watch.
+  // If the watcher has already been destroyed, this is a no-op.
+  virtual void CancelConnectivityStateWatch(ConnectivityStateWatcher* watcher)
+      GRPC_ABSTRACT;
+
+  // Attempt to connect to the backend.  Has no effect if already connected.
+  // If the subchannel is currently in backoff delay due to a previously
+  // failed attempt, the new connection attempt will not start until the
+  // backoff delay has elapsed.
+  virtual void AttemptToConnect() GRPC_ABSTRACT;
+
+  // Resets the subchannel's connection backoff state.  If AttemptToConnect()
+  // has been called since the subchannel entered TRANSIENT_FAILURE state,
+  // starts a new connection attempt immediately; otherwise, a new connection
+  // attempt will be started as soon as AttemptToConnect() is called.
+  virtual void ResetBackoff() GRPC_ABSTRACT;
+
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H */
index a973cbc..8e93d11 100644 (file)
@@ -88,7 +88,7 @@ UniquePtr<ServiceConfig::ParsedConfig> MessageSizeParser::ParsePerMethodParams(
     *error = GRPC_ERROR_CREATE_FROM_VECTOR("Message size parser", &error_list);
     return nullptr;
   }
-  return UniquePtr<ServiceConfig::ParsedConfig>(New<MessageSizeParsedObject>(
+  return UniquePtr<ServiceConfig::ParsedConfig>(New<MessageSizeParsedConfig>(
       max_request_message_bytes, max_response_message_bytes));
 }
 
@@ -102,7 +102,7 @@ size_t MessageSizeParser::ParserIndex() { return g_message_size_parser_index; }
 
 namespace {
 struct channel_data {
-  grpc_core::MessageSizeParsedObject::message_size_limits limits;
+  grpc_core::MessageSizeParsedConfig::message_size_limits limits;
   grpc_core::RefCountedPtr<grpc_core::ServiceConfig> svc_cfg;
 };
 
@@ -119,21 +119,21 @@ struct call_data {
     // 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.
-    const grpc_core::MessageSizeParsedObject* limits = nullptr;
+    const grpc_core::MessageSizeParsedConfig* limits = nullptr;
     grpc_core::ServiceConfig::CallData* svc_cfg_call_data = nullptr;
     if (args.context != nullptr) {
       svc_cfg_call_data = static_cast<grpc_core::ServiceConfig::CallData*>(
-          args.context[GRPC_SERVICE_CONFIG_CALL_DATA].value);
+          args.context[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
     }
     if (svc_cfg_call_data != nullptr) {
-      limits = static_cast<const grpc_core::MessageSizeParsedObject*>(
-          svc_cfg_call_data->GetMethodParsedObject(
+      limits = static_cast<const grpc_core::MessageSizeParsedConfig*>(
+          svc_cfg_call_data->GetMethodParsedConfig(
               grpc_core::MessageSizeParser::ParserIndex()));
     } else if (chand.svc_cfg != nullptr) {
       const auto* objs_vector =
-          chand.svc_cfg->GetMethodServiceConfigObjectsVector(args.path);
+          chand.svc_cfg->GetMethodParsedConfigVector(args.path);
       if (objs_vector != nullptr) {
-        limits = static_cast<const grpc_core::MessageSizeParsedObject*>(
+        limits = static_cast<const grpc_core::MessageSizeParsedConfig*>(
             (*objs_vector)[grpc_core::MessageSizeParser::ParserIndex()].get());
       }
     }
@@ -154,7 +154,7 @@ struct call_data {
   ~call_data() { GRPC_ERROR_UNREF(error); }
 
   grpc_core::CallCombiner* call_combiner;
-  grpc_core::MessageSizeParsedObject::message_size_limits limits;
+  grpc_core::MessageSizeParsedConfig::message_size_limits limits;
   // Receive closures are chained: we inject this closure as the
   // recv_message_ready up-call on transport_stream_op, and remember to
   // call our next_recv_message_ready member after handling it.
@@ -300,9 +300,9 @@ static int default_size(const grpc_channel_args* args,
   return without_minimal_stack;
 }
 
-grpc_core::MessageSizeParsedObject::message_size_limits get_message_size_limits(
+grpc_core::MessageSizeParsedConfig::message_size_limits get_message_size_limits(
     const grpc_channel_args* channel_args) {
-  grpc_core::MessageSizeParsedObject::message_size_limits lim;
+  grpc_core::MessageSizeParsedConfig::message_size_limits lim;
   lim.max_send_size =
       default_size(channel_args, GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH);
   lim.max_recv_size =
@@ -392,7 +392,7 @@ static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder,
   const grpc_channel_args* channel_args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
   bool enable = false;
-  grpc_core::MessageSizeParsedObject::message_size_limits lim =
+  grpc_core::MessageSizeParsedConfig::message_size_limits lim =
       get_message_size_limits(channel_args);
   if (lim.max_send_size != -1 || lim.max_recv_size != -1) {
     enable = true;
index cab8bd9..1dde55f 100644 (file)
@@ -26,14 +26,14 @@ extern const grpc_channel_filter grpc_message_size_filter;
 
 namespace grpc_core {
 
-class MessageSizeParsedObject : public ServiceConfig::ParsedConfig {
+class MessageSizeParsedConfig : public ServiceConfig::ParsedConfig {
  public:
   struct message_size_limits {
     int max_send_size;
     int max_recv_size;
   };
 
-  MessageSizeParsedObject(int max_send_size, int max_recv_size) {
+  MessageSizeParsedConfig(int max_send_size, int max_recv_size) {
     limits_.max_send_size = max_send_size;
     limits_.max_recv_size = max_recv_size;
   }
index 040ea20..8285ee7 100644 (file)
 
 #include "src/core/ext/transport/chttp2/server/chttp2_server.h"
 
-#include <grpc/grpc.h>
-
 #include <inttypes.h>
 #include <limits.h>
 #include <string.h>
 
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
@@ -289,6 +289,50 @@ static void server_destroy_listener(grpc_server* server, void* arg,
   grpc_tcp_server_unref(tcp_server);
 }
 
+static grpc_error* chttp2_server_add_acceptor(grpc_server* server,
+                                              const char* name,
+                                              grpc_channel_args* args) {
+  grpc_tcp_server* tcp_server = nullptr;
+  grpc_error* err = GRPC_ERROR_NONE;
+  server_state* state = nullptr;
+  const grpc_arg* arg = nullptr;
+  grpc_core::TcpServerFdHandler** arg_val = nullptr;
+  state = static_cast<server_state*>(gpr_zalloc(sizeof(*state)));
+  GRPC_CLOSURE_INIT(&state->tcp_server_shutdown_complete,
+                    tcp_server_shutdown_complete, state,
+                    grpc_schedule_on_exec_ctx);
+  err = grpc_tcp_server_create(&state->tcp_server_shutdown_complete, args,
+                               &tcp_server);
+  if (err != GRPC_ERROR_NONE) {
+    goto error;
+  }
+  state->server = server;
+  state->tcp_server = tcp_server;
+  state->args = args;
+  state->shutdown = true;
+  gpr_mu_init(&state->mu);
+  // TODO(yangg) channelz
+  arg = grpc_channel_args_find(args, name);
+  GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
+  arg_val = static_cast<grpc_core::TcpServerFdHandler**>(arg->value.pointer.p);
+  *arg_val = grpc_tcp_server_create_fd_handler(tcp_server);
+
+  grpc_server_add_listener(server, state, server_start_listener,
+                           server_destroy_listener, /* socket_uuid */ 0);
+  return err;
+
+/* Error path: cleanup and return */
+error:
+  GPR_ASSERT(err != GRPC_ERROR_NONE);
+  if (tcp_server) {
+    grpc_tcp_server_unref(tcp_server);
+  } else {
+    grpc_channel_args_destroy(args);
+    gpr_free(state);
+  }
+  return err;
+}
+
 grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr,
                                         grpc_channel_args* args,
                                         int* port_num) {
@@ -306,6 +350,10 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr,
 
   *port_num = -1;
 
+  if (strncmp(addr, "external:", 9) == 0) {
+    return chttp2_server_add_acceptor(server, addr, args);
+  }
+
   /* resolve address */
   err = grpc_blocking_resolve_address(addr, "https", &resolved);
   if (err != GRPC_ERROR_NONE) {
index ccc3077..48c3d00 100644 (file)
@@ -1720,7 +1720,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
 }
 
 static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error) {
-  /* callback remaining pings: they're not allowed to call into the transpot,
+  /* callback remaining pings: they're not allowed to call into the transport,
      and maybe they hold resources that need to be freed */
   grpc_chttp2_ping_queue* pq = &t->ping_queue;
   GPR_ASSERT(error != GRPC_ERROR_NONE);
@@ -2262,7 +2262,7 @@ void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
   if (closed_read) {
     for (int i = 0; i < 2; i++) {
       if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
-        s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
+        s->published_metadata[i] = GRPC_METADATA_PUBLISHED_AT_CLOSE;
       }
     }
     grpc_chttp2_maybe_complete_recv_initial_metadata(t, s);
index 6080a4b..74c305b 100644 (file)
@@ -104,23 +104,21 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
     uint8_t* end = nullptr;
     uint8_t* cur = nullptr;
 
-    grpc_slice slice = grpc_slice_buffer_take_first(slices);
-
-    beg = GRPC_SLICE_START_PTR(slice);
-    end = GRPC_SLICE_END_PTR(slice);
+    grpc_slice* slice = grpc_slice_buffer_peek_first(slices);
+    beg = GRPC_SLICE_START_PTR(*slice);
+    end = GRPC_SLICE_END_PTR(*slice);
     cur = beg;
     uint32_t message_flags;
-    char* msg;
 
     if (cur == end) {
-      grpc_slice_unref_internal(slice);
+      grpc_slice_buffer_remove_first(slices);
       continue;
     }
 
     switch (p->state) {
       case GRPC_CHTTP2_DATA_ERROR:
         p->state = GRPC_CHTTP2_DATA_ERROR;
-        grpc_slice_unref_internal(slice);
+        grpc_slice_buffer_remove_first(slices);
         return GRPC_ERROR_REF(p->error);
       case GRPC_CHTTP2_DATA_FH_0:
         s->stats.incoming.framing_bytes++;
@@ -133,24 +131,25 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
             p->is_frame_compressed = true; /* GPR_TRUE */
             break;
           default:
+            char* msg;
             gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
             p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
             p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
                                           static_cast<intptr_t>(s->id));
             gpr_free(msg);
-            msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
-            p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
-                                          grpc_slice_from_copied_string(msg));
-            gpr_free(msg);
+            p->error =
+                grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
+                                   grpc_dump_slice_to_slice(
+                                       *slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
             p->error =
                 grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
             p->state = GRPC_CHTTP2_DATA_ERROR;
-            grpc_slice_unref_internal(slice);
+            grpc_slice_buffer_remove_first(slices);
             return GRPC_ERROR_REF(p->error);
         }
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_1;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           continue;
         }
       /* fallthrough */
@@ -159,7 +158,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
         p->frame_size = (static_cast<uint32_t>(*cur)) << 24;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_2;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           continue;
         }
       /* fallthrough */
@@ -168,7 +167,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
         p->frame_size |= (static_cast<uint32_t>(*cur)) << 16;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_3;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           continue;
         }
       /* fallthrough */
@@ -177,7 +176,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
         p->frame_size |= (static_cast<uint32_t>(*cur)) << 8;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_4;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           continue;
         }
       /* fallthrough */
@@ -204,19 +203,18 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
           p->state = GRPC_CHTTP2_DATA_FH_0;
         }
         s->pending_byte_stream = true;
-
         if (cur != end) {
-          grpc_slice_buffer_undo_take_first(
-              slices, grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
-                                     static_cast<size_t>(end - beg)));
+          grpc_slice_buffer_sub_first(slices, static_cast<size_t>(cur - beg),
+                                      static_cast<size_t>(end - beg));
+        } else {
+          grpc_slice_buffer_remove_first(slices);
         }
-        grpc_slice_unref_internal(slice);
         return GRPC_ERROR_NONE;
       case GRPC_CHTTP2_DATA_FRAME: {
         GPR_ASSERT(p->parsing_frame != nullptr);
         GPR_ASSERT(slice_out != nullptr);
         if (cur == end) {
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           continue;
         }
         uint32_t remaining = static_cast<uint32_t>(end - cur);
@@ -224,32 +222,32 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
           s->stats.incoming.data_bytes += remaining;
           if (GRPC_ERROR_NONE !=
               (error = p->parsing_frame->Push(
-                   grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                   grpc_slice_sub(*slice, static_cast<size_t>(cur - beg),
                                   static_cast<size_t>(end - beg)),
                    slice_out))) {
-            grpc_slice_unref_internal(slice);
+            grpc_slice_buffer_remove_first(slices);
             return error;
           }
           if (GRPC_ERROR_NONE !=
               (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
-            grpc_slice_unref_internal(slice);
+            grpc_slice_buffer_remove_first(slices);
             return error;
           }
           p->parsing_frame = nullptr;
           p->state = GRPC_CHTTP2_DATA_FH_0;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           return GRPC_ERROR_NONE;
         } else if (remaining < p->frame_size) {
           s->stats.incoming.data_bytes += remaining;
           if (GRPC_ERROR_NONE !=
               (error = p->parsing_frame->Push(
-                   grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                   grpc_slice_sub(*slice, static_cast<size_t>(cur - beg),
                                   static_cast<size_t>(end - beg)),
                    slice_out))) {
             return error;
           }
           p->frame_size -= remaining;
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_remove_first(slices);
           return GRPC_ERROR_NONE;
         } else {
           GPR_ASSERT(remaining > p->frame_size);
@@ -257,30 +255,27 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
           if (GRPC_ERROR_NONE !=
               p->parsing_frame->Push(
                   grpc_slice_sub(
-                      slice, static_cast<size_t>(cur - beg),
+                      *slice, static_cast<size_t>(cur - beg),
                       static_cast<size_t>(cur + p->frame_size - beg)),
                   slice_out)) {
-            grpc_slice_unref_internal(slice);
+            grpc_slice_buffer_remove_first(slices);
             return error;
           }
           if (GRPC_ERROR_NONE !=
               (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
-            grpc_slice_unref_internal(slice);
+            grpc_slice_buffer_remove_first(slices);
             return error;
           }
           p->parsing_frame = nullptr;
           p->state = GRPC_CHTTP2_DATA_FH_0;
           cur += p->frame_size;
-          grpc_slice_buffer_undo_take_first(
-              slices, grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
-                                     static_cast<size_t>(end - beg)));
-          grpc_slice_unref_internal(slice);
+          grpc_slice_buffer_sub_first(slices, static_cast<size_t>(cur - beg),
+                                      static_cast<size_t>(end - beg));
           return GRPC_ERROR_NONE;
         }
       }
     }
   }
-
   return GRPC_ERROR_NONE;
 }
 
index ccde36c..cda09c3 100644 (file)
@@ -26,6 +26,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/transport/http2_errors.h"
 
 grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
@@ -102,9 +103,9 @@ grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
       error = grpc_error_set_int(
           grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"),
                              GRPC_ERROR_STR_GRPC_MESSAGE,
-                             grpc_slice_from_copied_string(message)),
+                             grpc_slice_from_moved_string(
+                                 grpc_core::UniquePtr<char>(message))),
           GRPC_ERROR_INT_HTTP2_ERROR, static_cast<intptr_t>(reason));
-      gpr_free(message);
     }
     grpc_chttp2_mark_stream_closed(t, s, true, true, error);
   }
index d2607e9..359ad27 100644 (file)
@@ -37,6 +37,7 @@
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/surface/validate_metadata.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/timeout_encoding.h"
 /* don't consider adding anything bigger than this to the hpack table */
 #define MAX_DECODER_SPACE_USAGE 512
 
-static grpc_slice_refcount terminal_slice_refcount;
+#define DATA_FRAME_HEADER_SIZE 9
+
+static grpc_slice_refcount terminal_slice_refcount(
+    grpc_slice_refcount::Type::STATIC);
 static const grpc_slice terminal_slice = {
     &terminal_slice_refcount, /* refcount */
     {{0, nullptr}}            /* data.refcounted */
@@ -80,7 +84,8 @@ typedef struct {
   bool use_true_binary_metadata;
 } framer_state;
 
-/* fills p (which is expected to be 9 bytes long) with a data frame header */
+/* fills p (which is expected to be DATA_FRAME_HEADER_SIZE bytes long)
+ * with a data frame header */
 static void fill_header(uint8_t* p, uint8_t type, uint32_t id, size_t len,
                         uint8_t flags) {
   GPR_ASSERT(len < 16777316);
@@ -107,15 +112,17 @@ static void finish_frame(framer_state* st, int is_header_boundary,
       static_cast<uint8_t>(
           (is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
           (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
-  st->stats->framing_bytes += 9;
+  st->stats->framing_bytes += DATA_FRAME_HEADER_SIZE;
   st->is_first_frame = 0;
 }
 
 /* begin a new frame: reserve off header space, remember how many bytes we'd
    output before beginning */
 static void begin_frame(framer_state* st) {
-  st->header_idx =
-      grpc_slice_buffer_add_indexed(st->output, GRPC_SLICE_MALLOC(9));
+  grpc_slice reserved;
+  reserved.refcount = nullptr;
+  reserved.data.inlined.length = DATA_FRAME_HEADER_SIZE;
+  st->header_idx = grpc_slice_buffer_add_indexed(st->output, reserved);
   st->output_length_at_start_of_frame = st->output->length;
 }
 
@@ -188,8 +195,9 @@ static void evict_entry(grpc_chttp2_hpack_compressor* c) {
 static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
                                            size_t elem_size) {
   uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
-  GPR_ASSERT(elem_size < 65536);
+  GPR_DEBUG_ASSERT(elem_size < 65536);
 
+  // TODO(arjunroy): Re-examine semantics
   if (elem_size > c->max_table_size) {
     while (c->table_size > 0) {
       evict_entry(c);
@@ -203,6 +211,7 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
   while (c->table_size + elem_size > c->max_table_size) {
     evict_entry(c);
   }
+  // TODO(arjunroy): Are we conflating size in bytes vs. membership?
   GPR_ASSERT(c->table_elems < c->max_table_size);
   c->table_elem_size[new_index % c->cap_table_elems] =
       static_cast<uint16_t>(elem_size);
@@ -215,19 +224,19 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
 // 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,
-                               grpc_mdelem elem, uint32_t new_index) {
+                               grpc_mdelem elem, uint32_t new_index,
+                               uint32_t key_hash) {
   if (new_index == 0) {
     return;
   }
 
-  uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
-
   /* Store the key into {entries,indices}_keys */
-  if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
-                    GRPC_MDKEY(elem))) {
+  if (grpc_slice_static_interned_equal(
+          c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) {
     c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
-  } else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
-                           GRPC_MDKEY(elem))) {
+  } else if (grpc_slice_static_interned_equal(
+                 c->entries_keys[HASH_FRAGMENT_3(key_hash)],
+                 GRPC_MDKEY(elem))) {
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
              &terminal_slice_refcount) {
@@ -255,22 +264,20 @@ static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
 
 /* add an element to the decoder table */
 static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
-                                grpc_mdelem elem, uint32_t new_index) {
+                                grpc_mdelem elem, uint32_t new_index,
+                                uint32_t elem_hash, uint32_t key_hash) {
   if (new_index == 0) {
     return;
   }
-  GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
-
-  uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
-  uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
-  uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
+  GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
 
   /* Store this element into {entries,indices}_elem */
-  if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
+  if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)],
+                                   elem)) {
     /* already there: update with new index */
     c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-  } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
-                            elem)) {
+  } else if (grpc_mdelem_both_interned_eq(
+                 c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem)) {
     /* already there (cuckoo): update with new index */
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
   } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
@@ -294,19 +301,19 @@ static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
   }
 
-  add_key_with_index(c, elem, new_index);
+  add_key_with_index(c, elem, new_index, key_hash);
 }
 
 static void add_elem(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
-                     size_t elem_size) {
+                     size_t elem_size, uint32_t elem_hash, uint32_t key_hash) {
   uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
-  add_elem_with_index(c, elem, new_index);
+  add_elem_with_index(c, elem, new_index, elem_hash, key_hash);
 }
 
 static void add_key(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
-                    size_t elem_size) {
+                    size_t elem_size, uint32_t key_hash) {
   uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
-  add_key_with_index(c, elem, new_index);
+  add_key_with_index(c, elem, new_index, key_hash);
 }
 
 static void emit_indexed(grpc_chttp2_hpack_compressor* c, uint32_t elem_index,
@@ -323,9 +330,14 @@ typedef struct {
   bool insert_null_before_wire_value;
 } wire_value;
 
+template <bool mdkey_definitely_interned>
 static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) {
   wire_value wire_val;
-  if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+  bool is_bin_hdr =
+      mdkey_definitely_interned
+          ? grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem))
+          : grpc_is_binary_header_internal(GRPC_MDKEY(elem));
+  if (is_bin_hdr) {
     if (true_binary_enabled) {
       GRPC_STATS_INC_HPACK_SEND_BINARY();
       wire_val.huffman_prefix = 0x00;
@@ -363,7 +375,7 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor* c,
                                framer_state* st) {
   GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX();
   uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
-  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
   size_t len_val = wire_value_length(value);
   uint32_t len_val_len;
   GPR_ASSERT(len_val <= UINT32_MAX);
@@ -380,7 +392,7 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor* c,
                               framer_state* st) {
   GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX();
   uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
-  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
   size_t len_val = wire_value_length(value);
   uint32_t len_val_len;
   GPR_ASSERT(len_val <= UINT32_MAX);
@@ -399,7 +411,7 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor* c,
   GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V();
   GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
   uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
-  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
   uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@@ -421,7 +433,7 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor* c,
   GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V();
   GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
   uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
-  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
   uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@@ -464,7 +476,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     char* k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
     char* v = nullptr;
-    if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+    if (grpc_is_binary_header_internal(GRPC_MDKEY(elem))) {
       v = grpc_dump_slice(GRPC_MDVALUE(elem), GPR_DUMP_HEX);
     } else {
       v = grpc_slice_to_c_string(GRPC_MDVALUE(elem));
@@ -488,27 +500,33 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
     return;
   }
 
-  uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
   uint32_t elem_hash = 0;
 
   if (elem_interned) {
-    uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
-    elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
+    if (GRPC_MDELEM_STORAGE(elem) == GRPC_MDELEM_STORAGE_INTERNED) {
+      elem_hash =
+          reinterpret_cast<grpc_core::InternedMetadata*>(GRPC_MDELEM_DATA(elem))
+              ->hash();
+    } else {
+      elem_hash =
+          reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(elem))
+              ->hash();
+    }
 
     inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum,
                c->filter_elems);
 
     /* is this elem currently in the decoders table? */
-
-    if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
+    if (grpc_mdelem_both_interned_eq(
+            c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
         c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
       /* HIT: complete element (first cuckoo hash) */
       emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
                    st);
       return;
     }
-
-    if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
+    if (grpc_mdelem_both_interned_eq(
+            c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
         c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
       /* HIT: complete element (second cuckoo hash) */
       emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
@@ -527,11 +545,12 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
                                c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
                                    c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
 
+  uint32_t key_hash = GRPC_MDKEY(elem).refcount->Hash(GRPC_MDKEY(elem));
   auto emit_maybe_add = [&should_add_elem, &elem, &st, &c, &indices_key,
-                         &decoder_space_usage] {
+                         &decoder_space_usage, &elem_hash, &key_hash] {
     if (should_add_elem) {
       emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem, decoder_space_usage);
+      add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
     } else {
       emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
     }
@@ -539,8 +558,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
 
   /* no hits for the elem... maybe there's a key? */
   indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
-  if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
-                    GRPC_MDKEY(elem)) &&
+  if (grpc_slice_static_interned_equal(
+          c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem)) &&
       indices_key > c->tail_remote_index) {
     /* HIT: key (first cuckoo hash) */
     emit_maybe_add();
@@ -548,8 +567,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
   }
 
   indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
-  if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
-                    GRPC_MDKEY(elem)) &&
+  if (grpc_slice_static_interned_equal(
+          c->entries_keys[HASH_FRAGMENT_3(key_hash)], GRPC_MDKEY(elem)) &&
       indices_key > c->tail_remote_index) {
     /* HIT: key (first cuckoo hash) */
     emit_maybe_add();
@@ -565,9 +584,9 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
     emit_lithdr_noidx_v(c, 0, elem, st);
   }
   if (should_add_elem) {
-    add_elem(c, elem, decoder_space_usage);
+    add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
   } else if (should_add_key) {
-    add_key(c, elem, decoder_space_usage);
+    add_key(c, elem, decoder_space_usage, key_hash);
   }
 }
 
@@ -692,18 +711,18 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
   }
   for (size_t i = 0; i < extra_headers_size; ++i) {
     grpc_mdelem md = *extra_headers[i];
-    uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
+    uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
     if (static_index) {
-      emit_indexed(c, static_index, &st);
+      emit_indexed(c, static_cast<uint32_t>(static_index), &st);
     } else {
       hpack_enc(c, md, &st);
     }
   }
   grpc_metadata_batch_assert_ok(metadata);
   for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) {
-    uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
+    uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
     if (static_index) {
-      emit_indexed(c, static_index, &st);
+      emit_indexed(c, static_cast<uint32_t>(static_index), &st);
     } else {
       hpack_enc(c, l->md, &st);
     }
index 6e42212..7d5c39e 100644 (file)
@@ -35,6 +35,7 @@
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/surface/validate_metadata.h"
 #include "src/core/lib/transport/http2_errors.h"
 
 typedef enum {
@@ -627,7 +628,7 @@ static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md,
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
     char* v = nullptr;
-    if (grpc_is_binary_header(GRPC_MDKEY(md))) {
+    if (grpc_is_binary_header_internal(GRPC_MDKEY(md))) {
       v = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX);
     } else {
       v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
@@ -1494,7 +1495,13 @@ static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
 /* check if a key represents a binary header or not */
 
 static bool is_binary_literal_header(grpc_chttp2_hpack_parser* p) {
-  return grpc_is_binary_header(
+  /* We know that either argument here is a reference counter slice.
+   * 1. If a result of grpc_slice_from_static_buffer, the refcount is set to
+   *    NoopRefcount.
+   * 2. If it's p->key.data.referenced, then p->key.copied was set to false,
+   *    which occurs in begin_parse_string() - where the refcount is set to
+   *    p->current_slice_refcount, which is not null. */
+  return grpc_is_refcounted_slice_binary_header(
       p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str,
                                                     p->key.data.copied.length)
                     : p->key.data.referenced);
@@ -1511,7 +1518,15 @@ static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
                            static_cast<intptr_t>(p->index)),
         GRPC_ERROR_INT_SIZE, static_cast<intptr_t>(p->table.num_ents));
   }
-  *is = grpc_is_binary_header(GRPC_MDKEY(elem));
+  /* We know that GRPC_MDKEY(elem) points to a reference counted slice since:
+   * 1. elem was a result of grpc_chttp2_hptbl_lookup
+   * 2. An item in this table is either static (see entries with
+   *    index < GRPC_CHTTP2_LAST_STATIC_ENTRY or added via
+   *    grpc_chttp2_hptbl_add).
+   * 3. If added via grpc_chttp2_hptbl_add, the entry is either static or
+   *    interned.
+   * 4. Both static and interned element slices have non-null refcounts. */
+  *is = grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem));
   return GRPC_ERROR_NONE;
 }
 
index 16aeb49..f9e97cc 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/surface/validate_metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
 
 extern grpc_core::TraceFlag grpc_http_trace;
@@ -375,9 +376,11 @@ static size_t get_base64_encoded_size(size_t raw_length) {
 
 size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
                                            bool use_true_binary_metadata) {
-  size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+  const uint8_t* key_buf = GRPC_SLICE_START_PTR(GRPC_MDKEY(elem));
+  size_t key_len = GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+  size_t overhead_and_key = 32 + key_len;
   size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
-  if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+  if (grpc_key_is_binary_header(key_buf, key_len)) {
     return overhead_and_key + (use_true_binary_metadata
                                    ? value_len + 1
                                    : get_base64_encoded_size(value_len));
@@ -385,13 +388,3 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
     return overhead_and_key + value_len;
   }
 }
-
-uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
-  if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
-    uint8_t index = GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table;
-    if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
-      return index + 1;  // Hpack static metadata element indices start at 1
-    }
-  }
-  return 0;
-}
index a0ffc6f..38f8bdd 100644 (file)
@@ -24,6 +24,7 @@
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/static_metadata.h"
 
 /* HPACK header table */
 
@@ -90,7 +91,15 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
 /* Returns the static hpack table index that corresponds to /a elem. Returns 0
   if /a elem is not statically stored or if it is not in the static hpack
   table */
-uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md);
+inline uintptr_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
+  uintptr_t index =
+      reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(md)) -
+      grpc_static_mdelem_table;
+  if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
+    return index + 1;  // Hpack static metadata element indices start at 1
+  }
+  return 0;
+}
 
 /* Find a key/value pair in the table... returns the index in the table of the
    most similar entry, or 0 if the value was not found */
index bfe7745..4ab46f9 100644 (file)
@@ -225,14 +225,14 @@ class Chttp2IncomingByteStream : public ByteStream {
   // TODO(roth): When I converted this class to C++, I wanted to make it
   // inherit from RefCounted or InternallyRefCounted instead of continuing
   // to use its own custom ref-counting code.  However, that would require
-  // using multiple inheritence, which sucks in general.  And to make matters
+  // using multiple inheritance, which sucks in general.  And to make matters
   // worse, it causes problems with our New<> and Delete<> wrappers.
   // Specifically, unless RefCounted is first in the list of parent classes,
   // it will see a different value of the address of the object than the one
   // we actually allocated, in which case gpr_free() will be called on a
   // different address than the one we got from gpr_malloc(), thus causing a
   // crash.  Given the fragility of depending on that, as well as a desire to
-  // avoid multiple inheritence in general, I've decided to leave this
+  // avoid multiple inheritance in general, I've decided to leave this
   // 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<>.
@@ -499,7 +499,7 @@ typedef enum {
   GRPC_METADATA_NOT_PUBLISHED,
   GRPC_METADATA_SYNTHESIZED_FROM_FAKE,
   GRPC_METADATA_PUBLISHED_FROM_WIRE,
-  GPRC_METADATA_PUBLISHED_AT_CLOSE
+  GRPC_METADATA_PUBLISHED_AT_CLOSE
 } grpc_published_metadata_method;
 
 struct grpc_chttp2_stream {
index 15648c0..1aa6d97 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/slice/slice_utils.h"
 #include "src/core/lib/transport/http2_errors.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/status_conversion.h"
@@ -410,53 +411,42 @@ static void on_initial_header(void* tp, grpc_mdelem md) {
     gpr_free(value);
   }
 
-  if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
-    // We don't use grpc_mdelem_eq here to avoid executing additional
-    // instructions. The reasoning is if the payload is not equal, we already
-    // know that the metadata elements are not equal because the md is
-    // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
-    // payloads are not equal, grpc_mdelem_eq executes more instructions to
-    // determine if they're equal or not.
-    if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
-        md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
-      s->seen_error = true;
-    }
-  } else {
-    if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
-        !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
-      /* TODO(ctiller): check for a status like " 0" */
-      s->seen_error = true;
-    }
-
-    if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
-      grpc_millis* cached_timeout = static_cast<grpc_millis*>(
-          grpc_mdelem_get_user_data(md, free_timeout));
-      grpc_millis timeout;
-      if (cached_timeout != nullptr) {
-        timeout = *cached_timeout;
-      } else {
-        if (GPR_UNLIKELY(
-                !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
-          char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
-          gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
-          gpr_free(val);
-          timeout = GRPC_MILLIS_INF_FUTURE;
-        }
-        if (GRPC_MDELEM_IS_INTERNED(md)) {
-          /* store the result */
-          cached_timeout =
-              static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
-          *cached_timeout = timeout;
-          grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
-        }
+  // If md.payload == GRPC_MDELEM_GRPC_STATUS_1 or GRPC_MDELEM_GRPC_STATUS_2,
+  // then we have seen an error. In fact, if it is a GRPC_STATUS and it's
+  // not equal to GRPC_MDELEM_GRPC_STATUS_0, then we have seen an error.
+  if (grpc_slice_eq_static_interned(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+      !grpc_mdelem_static_value_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+    /* TODO(ctiller): check for a status like " 0" */
+    s->seen_error = true;
+  } else if (grpc_slice_eq_static_interned(GRPC_MDKEY(md),
+                                           GRPC_MDSTR_GRPC_TIMEOUT)) {
+    grpc_millis* cached_timeout =
+        static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
+    grpc_millis timeout;
+    if (cached_timeout != nullptr) {
+      timeout = *cached_timeout;
+    } else {
+      if (GPR_UNLIKELY(
+              !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
+        char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+        gpr_free(val);
+        timeout = GRPC_MILLIS_INF_FUTURE;
       }
-      if (timeout != GRPC_MILLIS_INF_FUTURE) {
-        grpc_chttp2_incoming_metadata_buffer_set_deadline(
-            &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
+      if (GRPC_MDELEM_IS_INTERNED(md)) {
+        /* store the result */
+        cached_timeout =
+            static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
+        *cached_timeout = timeout;
+        grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
       }
-      GRPC_MDELEM_UNREF(md);
-      return;
     }
+    if (timeout != GRPC_MILLIS_INF_FUTURE) {
+      grpc_chttp2_incoming_metadata_buffer_set_deadline(
+          &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
+    }
+    GRPC_MDELEM_UNREF(md);
+    return;
   }
 
   const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
@@ -506,19 +496,11 @@ static void on_trailing_header(void* tp, grpc_mdelem md) {
     gpr_free(value);
   }
 
-  if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
-    // We don't use grpc_mdelem_eq here to avoid executing additional
-    // instructions. The reasoning is if the payload is not equal, we already
-    // know that the metadata elements are not equal because the md is
-    // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
-    // payloads are not equal, grpc_mdelem_eq executes more instructions to
-    // determine if they're equal or not.
-    if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
-        md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
-      s->seen_error = true;
-    }
-  } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
-             !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+  // If md.payload == GRPC_MDELEM_GRPC_STATUS_1 or GRPC_MDELEM_GRPC_STATUS_2,
+  // then we have seen an error. In fact, if it is a GRPC_STATUS and it's
+  // not equal to GRPC_MDELEM_GRPC_STATUS_0, then we have seen an error.
+  if (grpc_slice_eq_static_interned(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+      !grpc_mdelem_static_value_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
     /* TODO(ctiller): check for a status like " 0" */
     s->seen_error = true;
   }
index 320b529..3ddda26 100644 (file)
@@ -38,6 +38,7 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/validate_metadata.h"
 #include "src/core/lib/transport/metadata_batch.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/transport_impl.h"
@@ -419,7 +420,7 @@ static void convert_cronet_array_to_metadata(
     grpc_slice key = grpc_slice_intern(
         grpc_slice_from_static_string(header_array->headers[i].key));
     grpc_slice value;
-    if (grpc_is_binary_header(key)) {
+    if (grpc_is_refcounted_slice_binary_header(key)) {
       value = grpc_slice_from_static_string(header_array->headers[i].value);
       value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
           value, grpc_chttp2_base64_infer_length_after_decode(value)));
@@ -746,22 +747,23 @@ static void convert_metadata_to_cronet_headers(
     curr = curr->next;
     char* key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
     char* value;
-    if (grpc_is_binary_header(GRPC_MDKEY(mdelem))) {
+    if (grpc_is_binary_header_internal(GRPC_MDKEY(mdelem))) {
       grpc_slice wire_value = grpc_chttp2_base64_encode(GRPC_MDVALUE(mdelem));
       value = grpc_slice_to_c_string(wire_value);
       grpc_slice_unref_internal(wire_value);
     } else {
       value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
     }
-    if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) ||
-        grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_AUTHORITY)) {
+    if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) ||
+        grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem),
+                                      GRPC_MDSTR_AUTHORITY)) {
       /* Cronet populates these fields on its own */
       gpr_free(key);
       gpr_free(value);
       continue;
     }
-    if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_METHOD)) {
-      if (grpc_slice_eq(GRPC_MDVALUE(mdelem), GRPC_MDSTR_PUT)) {
+    if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_METHOD)) {
+      if (grpc_slice_eq_static_interned(GRPC_MDVALUE(mdelem), GRPC_MDSTR_PUT)) {
         *method = "PUT";
       } else {
         /* POST method in default*/
@@ -771,7 +773,7 @@ static void convert_metadata_to_cronet_headers(
       gpr_free(value);
       continue;
     }
-    if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_PATH)) {
+    if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_PATH)) {
       /* Create URL by appending :path value to the hostname */
       gpr_asprintf(pp_url, "https://%s%s", host, value);
       gpr_free(key);
@@ -803,7 +805,8 @@ static void parse_grpc_header(const uint8_t* data, int* length,
 
 static bool header_has_authority(grpc_linked_mdelem* head) {
   while (head != nullptr) {
-    if (grpc_slice_eq(GRPC_MDKEY(head->md), GRPC_MDSTR_AUTHORITY)) {
+    if (grpc_slice_eq_static_interned(GRPC_MDKEY(head->md),
+                                      GRPC_MDSTR_AUTHORITY)) {
       return true;
     }
     head = head->next;
index 0eed9a5..4b13037 100644 (file)
 #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/connectivity_state.h"
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/uri/uri_parser.h"
 
 namespace grpc_core {
 namespace channelz {
 
+//
+// channel arg code
+//
+
+namespace {
+
+void* parent_uuid_copy(void* p) { return p; }
+void parent_uuid_destroy(void* p) {}
+int parent_uuid_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
+const grpc_arg_pointer_vtable parent_uuid_vtable = {
+    parent_uuid_copy, parent_uuid_destroy, parent_uuid_cmp};
+
+}  // namespace
+
+grpc_arg MakeParentUuidArg(intptr_t parent_uuid) {
+  // We would ideally like to store the uuid in an integer argument.
+  // Unfortunately, that won't work, because intptr_t (the type used for
+  // uuids) doesn't fit in an int (the type used for integer args).
+  // So instead, we use a hack to store it as a pointer, because
+  // intptr_t should be the same size as void*.
+  static_assert(sizeof(intptr_t) <= sizeof(void*),
+                "can't fit intptr_t inside of void*");
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_CHANNELZ_PARENT_UUID),
+      reinterpret_cast<void*>(parent_uuid), &parent_uuid_vtable);
+}
+
+intptr_t GetParentUuidFromArgs(const grpc_channel_args& args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(&args, GRPC_ARG_CHANNELZ_PARENT_UUID);
+  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return 0;
+  return reinterpret_cast<intptr_t>(arg->value.pointer.p);
+}
+
+//
+// BaseNode
+//
+
 BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) {
   // The registry will set uuid_ under its lock.
   ChannelzRegistry::Register(this);
@@ -61,6 +100,10 @@ char* BaseNode::RenderJsonString() {
   return json_str;
 }
 
+//
+// CallCountingHelper
+//
+
 CallCountingHelper::CallCountingHelper() {
   num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
   per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>(
@@ -137,15 +180,17 @@ void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
   }
 }
 
-ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
-                         bool is_top_level_channel)
-    : BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel
-                                    : EntityType::kInternalChannel),
-      channel_(channel),
-      target_(UniquePtr<char>(grpc_channel_get_target(channel_))),
-      trace_(channel_tracer_max_nodes) {}
+//
+// ChannelNode
+//
 
-ChannelNode::~ChannelNode() {}
+ChannelNode::ChannelNode(UniquePtr<char> target,
+                         size_t channel_tracer_max_nodes, intptr_t parent_uuid)
+    : BaseNode(parent_uuid == 0 ? EntityType::kTopLevelChannel
+                                : EntityType::kInternalChannel),
+      target_(std::move(target)),
+      trace_(channel_tracer_max_nodes),
+      parent_uuid_(parent_uuid) {}
 
 grpc_json* ChannelNode::RenderJson() {
   // We need to track these three json objects to build our object
@@ -167,9 +212,19 @@ grpc_json* ChannelNode::RenderJson() {
                                            GRPC_JSON_OBJECT, false);
   json = data;
   json_iterator = nullptr;
-  // template method. Child classes may override this to add their specific
-  // functionality.
-  PopulateConnectivityState(json);
+  // connectivity state
+  // If low-order bit is on, then the field is set.
+  int state_field = connectivity_state_.Load(MemoryOrder::RELAXED);
+  if ((state_field & 1) != 0) {
+    grpc_connectivity_state state =
+        static_cast<grpc_connectivity_state>(state_field >> 1);
+    json = grpc_json_create_child(nullptr, json, "state", nullptr,
+                                  GRPC_JSON_OBJECT, false);
+    grpc_json_create_child(nullptr, json, "state",
+                           grpc_connectivity_state_name(state),
+                           GRPC_JSON_STRING, false);
+    json = data;
+  }
   // populate the target.
   GPR_ASSERT(target_.get() != nullptr);
   grpc_json_create_child(nullptr, json, "target", target_.get(),
@@ -189,13 +244,64 @@ grpc_json* ChannelNode::RenderJson() {
   return top_level_json;
 }
 
-RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
-    grpc_channel* channel, size_t channel_tracer_max_nodes,
-    bool is_top_level_channel) {
-  return MakeRefCounted<grpc_core::channelz::ChannelNode>(
-      channel, channel_tracer_max_nodes, is_top_level_channel);
+void ChannelNode::PopulateChildRefs(grpc_json* json) {
+  MutexLock lock(&child_mu_);
+  grpc_json* json_iterator = nullptr;
+  if (!child_subchannels_.empty()) {
+    grpc_json* array_parent = grpc_json_create_child(
+        nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false);
+    for (const auto& p : child_subchannels_) {
+      json_iterator =
+          grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
+                                 GRPC_JSON_OBJECT, false);
+      grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId",
+                                        p.first);
+    }
+  }
+  if (!child_channels_.empty()) {
+    grpc_json* array_parent = grpc_json_create_child(
+        nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false);
+    json_iterator = nullptr;
+    for (const auto& p : child_channels_) {
+      json_iterator =
+          grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
+                                 GRPC_JSON_OBJECT, false);
+      grpc_json_add_number_string_child(json_iterator, nullptr, "channelId",
+                                        p.first);
+    }
+  }
+}
+
+void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
+  // Store with low-order bit set to indicate that the field is set.
+  int state_field = (state << 1) + 1;
+  connectivity_state_.Store(state_field, MemoryOrder::RELAXED);
+}
+
+void ChannelNode::AddChildChannel(intptr_t child_uuid) {
+  MutexLock lock(&child_mu_);
+  child_channels_.insert(MakePair(child_uuid, true));
+}
+
+void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
+  MutexLock lock(&child_mu_);
+  child_channels_.erase(child_uuid);
 }
 
+void ChannelNode::AddChildSubchannel(intptr_t child_uuid) {
+  MutexLock lock(&child_mu_);
+  child_subchannels_.insert(MakePair(child_uuid, true));
+}
+
+void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
+  MutexLock lock(&child_mu_);
+  child_subchannels_.erase(child_uuid);
+}
+
+//
+// ServerNode
+//
+
 ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
     : BaseNode(EntityType::kServer),
       server_(server),
@@ -281,8 +387,14 @@ grpc_json* ServerNode::RenderJson() {
   return top_level_json;
 }
 
-static void PopulateSocketAddressJson(grpc_json* json, const char* name,
-                                      const char* addr_str) {
+//
+// SocketNode
+//
+
+namespace {
+
+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,
@@ -312,7 +424,6 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name,
                                            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);
@@ -332,6 +443,8 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name,
   grpc_uri_destroy(uri);
 }
 
+}  // namespace
+
 SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote)
     : BaseNode(EntityType::kSocket),
       local_(std::move(local)),
@@ -448,6 +561,10 @@ grpc_json* SocketNode::RenderJson() {
   return top_level_json;
 }
 
+//
+// ListenSocketNode
+//
+
 ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr)
     : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {}
 
index e543cda..f8acb53 100644 (file)
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/gprpp/inlined_vector.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/map.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/json/json.h"
 
-// Channel arg key for client channel factory.
-#define GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC \
-  "grpc.channelz_channel_node_creation_func"
+// Channel arg key for channelz node.
+#define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node"
 
-// Channel arg key to signal that the channel is an internal channel.
-#define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \
-  "grpc.channelz_channel_is_internal_channel"
+// Channel arg key to encode the channelz uuid of the channel's parent.
+#define GRPC_ARG_CHANNELZ_PARENT_UUID "grpc.channelz_parent_uuid"
 
 /** This is the default value for whether or not to enable channelz. If
  * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */
@@ -54,6 +54,10 @@ namespace grpc_core {
 
 namespace channelz {
 
+// Helpers for getting and setting GRPC_ARG_CHANNELZ_PARENT_UUID.
+grpc_arg MakeParentUuidArg(intptr_t parent_uuid);
+intptr_t GetParentUuidFromArgs(const grpc_channel_args& args);
+
 // TODO(ncteisen), this only contains the uuids of the children for now,
 // since that is all that is strictly needed. In a future enhancement we will
 // add human readable names as in the channelz.proto
@@ -147,38 +151,13 @@ class CallCountingHelper {
 // Handles channelz bookkeeping for channels
 class ChannelNode : public BaseNode {
  public:
-  static RefCountedPtr<ChannelNode> MakeChannelNode(
-      grpc_channel* channel, size_t channel_tracer_max_nodes,
-      bool is_top_level_channel);
+  ChannelNode(UniquePtr<char> target, size_t channel_tracer_max_nodes,
+              intptr_t parent_uuid);
 
-  ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
-              bool is_top_level_channel);
-  ~ChannelNode() override;
+  intptr_t parent_uuid() const { return parent_uuid_; }
 
   grpc_json* RenderJson() override;
 
-  // template methods. RenderJSON uses these methods to render its JSON
-  // representation. These are virtual so that children classes may provide
-  // their specific mechanism for populating these parts of the channelz
-  // object.
-  //
-  // ChannelNode does not have a notion of connectivity state or child refs,
-  // so it leaves these implementations blank.
-  //
-  // This is utilizing the template method design pattern.
-  //
-  // TODO(ncteisen): remove these template methods in favor of manual traversal
-  // and mutation of the grpc_json object.
-  virtual void PopulateConnectivityState(grpc_json* json) {}
-  virtual void PopulateChildRefs(grpc_json* json) {}
-
-  void MarkChannelDestroyed() {
-    GPR_ASSERT(channel_ != nullptr);
-    channel_ = nullptr;
-  }
-
-  bool ChannelIsDestroyed() { return channel_ == nullptr; }
-
   // proxy methods to composed classes.
   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
     trace_.AddTraceEvent(severity, data);
@@ -193,13 +172,35 @@ class ChannelNode : public BaseNode {
   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
 
+  void SetConnectivityState(grpc_connectivity_state state);
+
+  void AddChildChannel(intptr_t child_uuid);
+  void RemoveChildChannel(intptr_t child_uuid);
+
+  void AddChildSubchannel(intptr_t child_uuid);
+  void RemoveChildSubchannel(intptr_t child_uuid);
+
  private:
+  void PopulateChildRefs(grpc_json* json);
+
   // to allow the channel trace test to access trace_.
   friend class testing::ChannelNodePeer;
-  grpc_channel* channel_ = nullptr;
+
   UniquePtr<char> target_;
   CallCountingHelper call_counter_;
   ChannelTrace trace_;
+  const intptr_t parent_uuid_;
+
+  // Least significant bit indicates whether the value is set.  Remaining
+  // bits are a grpc_connectivity_state value.
+  Atomic<int> connectivity_state_{0};
+
+  Mutex child_mu_;  // Guards child maps below.
+  // TODO(roth): We don't actually use the values here, only the keys, so
+  // these should be sets instead of maps, but we don't currently have a set
+  // implementation.  Change this if/when we have one.
+  Map<intptr_t, bool> child_channels_;
+  Map<intptr_t, bool> child_subchannels_;
 };
 
 // Handles channelz bookkeeping for servers
@@ -285,11 +286,6 @@ class ListenSocketNode : public BaseNode {
   UniquePtr<char> local_addr_;
 };
 
-// Creation functions
-
-typedef RefCountedPtr<ChannelNode> (*ChannelNodeCreationFunc)(grpc_channel*,
-                                                              size_t, bool);
-
 }  // namespace channelz
 }  // namespace grpc_core
 
index b6a660b..553e1fe 100644 (file)
@@ -18,6 +18,9 @@
 
 #include <grpc/impl/codegen/port_platform.h>
 
+#include <algorithm>
+#include <cstring>
+
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/channel/channelz.h"
 #include "src/core/lib/channel/channelz_registry.h"
@@ -29,8 +32,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
-#include <cstring>
-
 namespace grpc_core {
 namespace channelz {
 namespace {
@@ -51,102 +52,58 @@ ChannelzRegistry* ChannelzRegistry::Default() {
   return g_channelz_registry;
 }
 
-ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }
-
-ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
-
 void ChannelzRegistry::InternalRegister(BaseNode* node) {
   MutexLock lock(&mu_);
-  entities_.push_back(node);
   node->uuid_ = ++uuid_generator_;
-}
-
-void ChannelzRegistry::MaybePerformCompactionLocked() {
-  constexpr double kEmptinessTheshold = 1. / 3;
-  double emptiness_ratio =
-      double(num_empty_slots_) / double(entities_.capacity());
-  if (emptiness_ratio > kEmptinessTheshold) {
-    int front = 0;
-    for (size_t i = 0; i < entities_.size(); ++i) {
-      if (entities_[i] != nullptr) {
-        entities_[front++] = entities_[i];
-      }
-    }
-    for (int i = 0; i < num_empty_slots_; ++i) {
-      entities_.pop_back();
-    }
-    num_empty_slots_ = 0;
-  }
-}
-
-int ChannelzRegistry::FindByUuidLocked(intptr_t target_uuid,
-                                       bool direct_hit_needed) {
-  int left = 0;
-  int right = int(entities_.size() - 1);
-  while (left <= right) {
-    int true_middle = left + (right - left) / 2;
-    int first_non_null = true_middle;
-    while (first_non_null < right && entities_[first_non_null] == nullptr) {
-      first_non_null++;
-    }
-    if (entities_[first_non_null] == nullptr) {
-      right = true_middle - 1;
-      continue;
-    }
-    intptr_t uuid = entities_[first_non_null]->uuid();
-    if (uuid == target_uuid) {
-      return int(first_non_null);
-    }
-    if (uuid < target_uuid) {
-      left = first_non_null + 1;
-    } else {
-      right = true_middle - 1;
-    }
-  }
-  return direct_hit_needed ? -1 : left;
+  node_map_[node->uuid_] = node;
 }
 
 void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
   GPR_ASSERT(uuid >= 1);
   MutexLock lock(&mu_);
   GPR_ASSERT(uuid <= uuid_generator_);
-  int idx = FindByUuidLocked(uuid, true);
-  GPR_ASSERT(idx >= 0);
-  entities_[idx] = nullptr;
-  num_empty_slots_++;
-  MaybePerformCompactionLocked();
+  node_map_.erase(uuid);
 }
 
-BaseNode* ChannelzRegistry::InternalGet(intptr_t uuid) {
+RefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
   MutexLock lock(&mu_);
   if (uuid < 1 || uuid > uuid_generator_) {
     return nullptr;
   }
-  int idx = FindByUuidLocked(uuid, true);
-  return idx < 0 ? nullptr : entities_[idx];
+  auto it = node_map_.find(uuid);
+  if (it == node_map_.end()) return nullptr;
+  // Found node.  Return only if its refcount is not zero (i.e., when we
+  // know that there is no other thread about to destroy it).
+  BaseNode* node = it->second;
+  if (!node->RefIfNonZero()) return nullptr;
+  return RefCountedPtr<BaseNode>(node);
 }
 
 char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
-  MutexLock lock(&mu_);
   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
   grpc_json* json = top_level_json;
   grpc_json* json_iterator = nullptr;
-  InlinedVector<BaseNode*, 10> top_level_channels;
-  bool reached_pagination_limit = false;
-  int start_idx = GPR_MAX(FindByUuidLocked(start_channel_id, false), 0);
-  for (size_t i = start_idx; i < entities_.size(); ++i) {
-    if (entities_[i] != nullptr &&
-        entities_[i]->type() ==
-            grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
-        entities_[i]->uuid() >= start_channel_id) {
-      // check if we are over pagination limit to determine if we need to set
-      // the "end" element. If we don't go through this block, we know that
-      // when the loop terminates, we have <= to kPaginationLimit.
-      if (top_level_channels.size() == kPaginationLimit) {
-        reached_pagination_limit = true;
-        break;
+  InlinedVector<RefCountedPtr<BaseNode>, 10> top_level_channels;
+  RefCountedPtr<BaseNode> node_after_pagination_limit;
+  {
+    MutexLock lock(&mu_);
+    for (auto it = node_map_.lower_bound(start_channel_id);
+         it != node_map_.end(); ++it) {
+      BaseNode* node = it->second;
+      if (node->type() == BaseNode::EntityType::kTopLevelChannel &&
+          node->RefIfNonZero()) {
+        // Check if we are over pagination limit to determine if we need to set
+        // the "end" element. If we don't go through this block, we know that
+        // when the loop terminates, we have <= to kPaginationLimit.
+        // Note that because we have already increased this node's
+        // refcount, we need to decrease it, but we can't unref while
+        // holding the lock, because this may lead to a deadlock.
+        if (top_level_channels.size() == kPaginationLimit) {
+          node_after_pagination_limit.reset(node);
+          break;
+        }
+        top_level_channels.emplace_back(node);
       }
-      top_level_channels.push_back(entities_[i]);
     }
   }
   if (!top_level_channels.empty()) {
@@ -159,7 +116,7 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
           grpc_json_link_child(array_parent, channel_json, json_iterator);
     }
   }
-  if (!reached_pagination_limit) {
+  if (node_after_pagination_limit == nullptr) {
     grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE,
                            false);
   }
@@ -169,26 +126,30 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
 }
 
 char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
-  MutexLock lock(&mu_);
   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
   grpc_json* json = top_level_json;
   grpc_json* json_iterator = nullptr;
-  InlinedVector<BaseNode*, 10> servers;
-  bool reached_pagination_limit = false;
-  int start_idx = GPR_MAX(FindByUuidLocked(start_server_id, false), 0);
-  for (size_t i = start_idx; i < entities_.size(); ++i) {
-    if (entities_[i] != nullptr &&
-        entities_[i]->type() ==
-            grpc_core::channelz::BaseNode::EntityType::kServer &&
-        entities_[i]->uuid() >= start_server_id) {
-      // check if we are over pagination limit to determine if we need to set
-      // the "end" element. If we don't go through this block, we know that
-      // when the loop terminates, we have <= to kPaginationLimit.
-      if (servers.size() == kPaginationLimit) {
-        reached_pagination_limit = true;
-        break;
+  InlinedVector<RefCountedPtr<BaseNode>, 10> servers;
+  RefCountedPtr<BaseNode> node_after_pagination_limit;
+  {
+    MutexLock lock(&mu_);
+    for (auto it = node_map_.lower_bound(start_server_id);
+         it != node_map_.end(); ++it) {
+      BaseNode* node = it->second;
+      if (node->type() == BaseNode::EntityType::kServer &&
+          node->RefIfNonZero()) {
+        // Check if we are over pagination limit to determine if we need to set
+        // the "end" element. If we don't go through this block, we know that
+        // when the loop terminates, we have <= to kPaginationLimit.
+        // Note that because we have already increased this node's
+        // refcount, we need to decrease it, but we can't unref while
+        // holding the lock, because this may lead to a deadlock.
+        if (servers.size() == kPaginationLimit) {
+          node_after_pagination_limit.reset(node);
+          break;
+        }
+        servers.emplace_back(node);
       }
-      servers.push_back(entities_[i]);
     }
   }
   if (!servers.empty()) {
@@ -201,7 +162,7 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
           grpc_json_link_child(array_parent, server_json, json_iterator);
     }
   }
-  if (!reached_pagination_limit) {
+  if (node_after_pagination_limit == nullptr) {
     grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE,
                            false);
   }
@@ -211,14 +172,21 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
 }
 
 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);
+  InlinedVector<RefCountedPtr<BaseNode>, 10> nodes;
+  {
+    MutexLock lock(&mu_);
+    for (auto& p : node_map_) {
+      BaseNode* node = p.second;
+      if (node->RefIfNonZero()) {
+        nodes.emplace_back(node);
+      }
     }
   }
+  for (size_t i = 0; i < nodes.size(); ++i) {
+    char* json = nodes[i]->RenderJsonString();
+    gpr_log(GPR_INFO, "%s", json);
+    gpr_free(json);
+  }
 }
 
 }  // namespace channelz
@@ -234,7 +202,7 @@ char* grpc_channelz_get_servers(intptr_t start_server_id) {
 }
 
 char* grpc_channelz_get_server(intptr_t server_id) {
-  grpc_core::channelz::BaseNode* server_node =
+  grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> server_node =
       grpc_core::channelz::ChannelzRegistry::Get(server_id);
   if (server_node == nullptr ||
       server_node->type() !=
@@ -254,7 +222,7 @@ char* grpc_channelz_get_server(intptr_t server_id) {
 char* grpc_channelz_get_server_sockets(intptr_t server_id,
                                        intptr_t start_socket_id,
                                        intptr_t max_results) {
-  grpc_core::channelz::BaseNode* base_node =
+  grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> base_node =
       grpc_core::channelz::ChannelzRegistry::Get(server_id);
   if (base_node == nullptr ||
       base_node->type() != grpc_core::channelz::BaseNode::EntityType::kServer) {
@@ -263,12 +231,12 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id,
   // This cast is ok since we have just checked to make sure base_node is
   // actually a server node
   grpc_core::channelz::ServerNode* server_node =
-      static_cast<grpc_core::channelz::ServerNode*>(base_node);
+      static_cast<grpc_core::channelz::ServerNode*>(base_node.get());
   return server_node->RenderServerSockets(start_socket_id, max_results);
 }
 
 char* grpc_channelz_get_channel(intptr_t channel_id) {
-  grpc_core::channelz::BaseNode* channel_node =
+  grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> channel_node =
       grpc_core::channelz::ChannelzRegistry::Get(channel_id);
   if (channel_node == nullptr ||
       (channel_node->type() !=
@@ -288,7 +256,7 @@ char* grpc_channelz_get_channel(intptr_t channel_id) {
 }
 
 char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
-  grpc_core::channelz::BaseNode* subchannel_node =
+  grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> subchannel_node =
       grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
   if (subchannel_node == nullptr ||
       subchannel_node->type() !=
@@ -306,7 +274,7 @@ char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
 }
 
 char* grpc_channelz_get_socket(intptr_t socket_id) {
-  grpc_core::channelz::BaseNode* socket_node =
+  grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> socket_node =
       grpc_core::channelz::ChannelzRegistry::Get(socket_id);
   if (socket_node == nullptr ||
       socket_node->type() !=
index 73b3307..e04d7c4 100644 (file)
 
 #include <grpc/impl/codegen/port_platform.h>
 
+#include <stdint.h>
+
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/channel/channelz.h"
-#include "src/core/lib/gprpp/inlined_vector.h"
-
-#include <stdint.h>
+#include "src/core/lib/gprpp/map.h"
+#include "src/core/lib/gprpp/sync.h"
 
 namespace grpc_core {
 namespace channelz {
 
-namespace testing {
-class ChannelzRegistryPeer;
-}
-
 // singleton registry object to track all objects that are needed to support
 // channelz bookkeeping. All objects share globally distributed uuids.
 class ChannelzRegistry {
@@ -48,7 +45,9 @@ class ChannelzRegistry {
     return Default()->InternalRegister(node);
   }
   static void Unregister(intptr_t uuid) { Default()->InternalUnregister(uuid); }
-  static BaseNode* Get(intptr_t uuid) { return Default()->InternalGet(uuid); }
+  static RefCountedPtr<BaseNode> Get(intptr_t uuid) {
+    return Default()->InternalGet(uuid);
+  }
 
   // Returns the allocated JSON string that represents the proto
   // GetTopChannelsResponse as per channelz.proto.
@@ -67,13 +66,6 @@ class ChannelzRegistry {
   static void LogAllEntities() { Default()->InternalLogAllEntities(); }
 
  private:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
-  friend class testing::ChannelzRegistryPeer;
-
-  ChannelzRegistry();
-  ~ChannelzRegistry();
-
   // Returned the singleton instance of ChannelzRegistry;
   static ChannelzRegistry* Default();
 
@@ -86,27 +78,17 @@ class ChannelzRegistry {
 
   // if object with uuid has previously been registered as the correct type,
   // returns the void* associated with that uuid. Else returns nullptr.
-  BaseNode* InternalGet(intptr_t uuid);
+  RefCountedPtr<BaseNode> InternalGet(intptr_t uuid);
 
   char* InternalGetTopChannels(intptr_t start_channel_id);
   char* InternalGetServers(intptr_t start_server_id);
 
-  // If entities_ has over a certain threshold of empty slots, it will
-  // compact the vector and move all used slots to the front.
-  void MaybePerformCompactionLocked();
-
-  // Performs binary search on entities_ to find the index with that uuid.
-  // If direct_hit_needed, then will return -1 in case of absence.
-  // 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_;
+  Mutex mu_;
+  Map<intptr_t, BaseNode*> node_map_;
   intptr_t uuid_generator_ = 0;
-  int num_empty_slots_ = 0;
 };
 
 }  // namespace channelz
index fd9d0ce..e8a0245 100644 (file)
@@ -36,7 +36,7 @@ typedef enum {
   GRPC_CONTEXT_TRAFFIC,
 
   /// Holds a pointer to ServiceConfig::CallData associated with this call.
-  GRPC_SERVICE_CONFIG_CALL_DATA,
+  GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA,
 
   GRPC_CONTEXT_COUNT
 } grpc_context_index;
index 27ff250..ad0bc87 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <string.h>
 
+#include <grpc/impl/codegen/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
@@ -226,6 +227,11 @@ void HandshakeManager::DoHandshake(grpc_endpoint* endpoint,
     args_.read_buffer =
         static_cast<grpc_slice_buffer*>(gpr_malloc(sizeof(*args_.read_buffer)));
     grpc_slice_buffer_init(args_.read_buffer);
+    if (acceptor != nullptr && acceptor->external_connection &&
+        acceptor->pending_data != nullptr) {
+      grpc_slice_buffer_swap(args_.read_buffer,
+                             &(acceptor->pending_data->data.raw.slice_buffer));
+    }
     // Initialize state needed for calling handshakers.
     acceptor_ = acceptor;
     GRPC_CLOSURE_INIT(&call_next_handshaker_,
index 9139fa0..a3a069d 100644 (file)
@@ -26,6 +26,7 @@
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/compression_internal.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/slice/slice_utils.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -42,16 +43,17 @@ int grpc_compression_algorithm_is_stream(grpc_compression_algorithm algorithm) {
 
 int grpc_compression_algorithm_parse(grpc_slice name,
                                      grpc_compression_algorithm* algorithm) {
-  if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) {
+  if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_IDENTITY)) {
     *algorithm = GRPC_COMPRESS_NONE;
     return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) {
+  } else if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_DEFLATE)) {
     *algorithm = GRPC_COMPRESS_DEFLATE;
     return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) {
+  } else if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_GZIP)) {
     *algorithm = GRPC_COMPRESS_GZIP;
     return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_STREAM_SLASH_GZIP)) {
+  } else if (grpc_slice_eq_static_interned(name,
+                                           GRPC_MDSTR_STREAM_SLASH_GZIP)) {
     *algorithm = GRPC_COMPRESS_STREAM_GZIP;
     return 1;
   } else {
@@ -148,10 +150,13 @@ grpc_slice grpc_compression_algorithm_slice(
 
 grpc_compression_algorithm grpc_compression_algorithm_from_slice(
     const grpc_slice& str) {
-  if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP;
-  if (grpc_slice_eq(str, GRPC_MDSTR_STREAM_SLASH_GZIP))
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY))
+    return GRPC_COMPRESS_NONE;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_DEFLATE))
+    return GRPC_COMPRESS_DEFLATE;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP))
+    return GRPC_COMPRESS_GZIP;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_STREAM_SLASH_GZIP))
     return GRPC_COMPRESS_STREAM_GZIP;
   return GRPC_COMPRESS_ALGORITHMS_COUNT;
 }
index 65a36de..e0d73ef 100644 (file)
@@ -26,6 +26,7 @@
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/compression_internal.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/slice/slice_utils.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/transport/static_metadata.h"
 
 
 grpc_message_compression_algorithm
 grpc_message_compression_algorithm_from_slice(const grpc_slice& str) {
-  if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY))
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY))
     return GRPC_MESSAGE_COMPRESS_NONE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE))
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_DEFLATE))
     return GRPC_MESSAGE_COMPRESS_DEFLATE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_MESSAGE_COMPRESS_GZIP;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP))
+    return GRPC_MESSAGE_COMPRESS_GZIP;
   return GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT;
 }
 
 grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice(
     const grpc_slice& str) {
-  if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_STREAM_COMPRESS_NONE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_STREAM_COMPRESS_GZIP;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY))
+    return GRPC_STREAM_COMPRESS_NONE;
+  if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP))
+    return GRPC_STREAM_COMPRESS_GZIP;
   return GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT;
 }
 
@@ -244,13 +248,13 @@ grpc_message_compression_algorithm grpc_message_compression_algorithm_for_level(
 
 int grpc_message_compression_algorithm_parse(
     grpc_slice value, grpc_message_compression_algorithm* algorithm) {
-  if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) {
+  if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) {
     *algorithm = GRPC_MESSAGE_COMPRESS_NONE;
     return 1;
-  } else if (grpc_slice_eq(value, GRPC_MDSTR_DEFLATE)) {
+  } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_DEFLATE)) {
     *algorithm = GRPC_MESSAGE_COMPRESS_DEFLATE;
     return 1;
-  } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) {
+  } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) {
     *algorithm = GRPC_MESSAGE_COMPRESS_GZIP;
     return 1;
   } else {
@@ -263,10 +267,10 @@ int grpc_message_compression_algorithm_parse(
 
 int grpc_stream_compression_algorithm_parse(
     grpc_slice value, grpc_stream_compression_algorithm* algorithm) {
-  if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) {
+  if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) {
     *algorithm = GRPC_STREAM_COMPRESS_NONE;
     return 1;
-  } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) {
+  } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) {
     *algorithm = GRPC_STREAM_COMPRESS_GZIP;
     return 1;
   } else {
index da00736..73947a2 100644 (file)
@@ -35,7 +35,7 @@ typedef enum {
   GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT
 } grpc_message_compression_algorithm;
 
-/** Stream compresssion algorithms supported by gRPC */
+/** Stream compression algorithms supported by gRPC */
 typedef enum {
   GRPC_STREAM_COMPRESS_NONE = 0,
   GRPC_STREAM_COMPRESS_GZIP,
index 46cb3da..e085798 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "src/core/lib/compression/stream_compression.h"
 #include "src/core/lib/compression/stream_compression_gzip.h"
+#include "src/core/lib/slice/slice_utils.h"
 
 extern const grpc_stream_compression_vtable
     grpc_stream_compression_identity_vtable;
@@ -65,11 +66,11 @@ void grpc_stream_compression_context_destroy(
 int grpc_stream_compression_method_parse(
     grpc_slice value, bool is_compress,
     grpc_stream_compression_method* method) {
-  if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) {
+  if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) {
     *method = is_compress ? GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS
                           : GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS;
     return 1;
-  } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) {
+  } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) {
     *method = is_compress ? GRPC_STREAM_COMPRESSION_GZIP_COMPRESS
                           : GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS;
     return 1;
index c80f2f8..7328c3e 100644 (file)
@@ -68,7 +68,7 @@ struct grpc_stream_compression_vtable {
  * at the end of compression. Emits at most \a max_output_size compressed bytes
  * into \a out. If all the bytes in input buffer \a in are depleted and \a flush
  * is not GRPC_STREAM_COMPRESSION_FLUSH_NONE, the corresponding flush method is
- * executed. The total number of bytes emitted is outputed in \a output_size.
+ * executed. The total number of bytes emitted is outputted in \a output_size.
  *
  * A SYNC flush indicates that the entire messages in \a in can be decompressed
  * from \a out. A FINISH flush implies a SYNC flush, and that any further
@@ -85,7 +85,7 @@ bool grpc_stream_compress(grpc_stream_compression_context* ctx,
  * Decompress bytes provided in \a in with a given context. Emits at most \a
  * max_output_size decompressed bytes into \a out. If decompression process
  * reached the end of a gzip stream, \a end_of_context is set to true; otherwise
- * it is set to false. The total number of bytes emitted is outputed in \a
+ * it is set to false. The total number of bytes emitted is outputted in \a
  * output_size.
  */
 bool grpc_stream_decompress(grpc_stream_compression_context* ctx,
index bffdb1f..452b22b 100644 (file)
@@ -53,25 +53,25 @@ static bool gzip_flate(grpc_stream_compression_context_gzip* ctx,
     ctx->zs.avail_out = static_cast<uInt>(slice_size);
     ctx->zs.next_out = GRPC_SLICE_START_PTR(slice_out);
     while (ctx->zs.avail_out > 0 && in->length > 0 && !eoc) {
-      grpc_slice slice = grpc_slice_buffer_take_first(in);
-      ctx->zs.avail_in = static_cast<uInt> GRPC_SLICE_LENGTH(slice);
-      ctx->zs.next_in = GRPC_SLICE_START_PTR(slice);
+      grpc_slice* slice = grpc_slice_buffer_peek_first(in);
+      ctx->zs.avail_in = static_cast<uInt> GRPC_SLICE_LENGTH(*slice);
+      ctx->zs.next_in = GRPC_SLICE_START_PTR(*slice);
       r = ctx->flate(&ctx->zs, Z_NO_FLUSH);
       if (r < 0 && r != Z_BUF_ERROR) {
         gpr_log(GPR_ERROR, "zlib error (%d)", r);
         grpc_slice_unref_internal(slice_out);
-        grpc_slice_unref_internal(slice);
+        grpc_slice_buffer_remove_first(in);
         return false;
       } else if (r == Z_STREAM_END && ctx->flate == inflate) {
         eoc = true;
       }
       if (ctx->zs.avail_in > 0) {
-        grpc_slice_buffer_undo_take_first(
-            in,
-            grpc_slice_sub(slice, GRPC_SLICE_LENGTH(slice) - ctx->zs.avail_in,
-                           GRPC_SLICE_LENGTH(slice)));
+        grpc_slice_buffer_sub_first(
+            in, GRPC_SLICE_LENGTH(*slice) - ctx->zs.avail_in,
+            GRPC_SLICE_LENGTH(*slice));
+      } else {
+        grpc_slice_buffer_remove_first(in);
       }
-      grpc_slice_unref_internal(slice);
     }
     if (flush != 0 && ctx->zs.avail_out > 0 && !eoc) {
       GPR_ASSERT(in->length == 0);
index 11db17c..f5016c6 100644 (file)
@@ -26,7 +26,7 @@
 /* Env utility functions */
 
 /* Gets the environment variable value with the specified name.
-   Returns a newly allocated string. It is the responsability of the caller to
+   Returns a newly allocated string. It is the responsibility of the caller to
    gpr_free the return value if not NULL (which means that the environment
    variable exists). */
 char* gpr_getenv(const char* name);
index 31d5fde..a39f56e 100644 (file)
@@ -126,7 +126,8 @@ static void asciidump(dump_out* out, const char* buf, size_t len) {
   }
 }
 
-char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
+char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags,
+                          size_t* out_len) {
   dump_out out = dump_out_create();
   if (flags & GPR_DUMP_HEX) {
     hexdump(&out, buf, len);
@@ -135,9 +136,15 @@ char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
     asciidump(&out, buf, len);
   }
   dump_out_append(&out, 0);
+  *out_len = out.length;
   return out.data;
 }
 
+char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
+  size_t unused;
+  return gpr_dump_return_len(buf, len, flags, &unused);
+}
+
 int gpr_parse_bytes_to_uint32(const char* buf, size_t len, uint32_t* result) {
   uint32_t out = 0;
   uint32_t new_val;
index c5efcec..bf59db7 100644 (file)
 #define GPR_DUMP_HEX 0x00000001
 #define GPR_DUMP_ASCII 0x00000002
 
-/* Converts array buf, of length len, into a C string  according to the flags.
+/* Converts array buf, of length len, into a C string according to the flags.
    Result should be freed with gpr_free() */
 char* gpr_dump(const char* buf, size_t len, uint32_t flags);
+/* Converts array buf, of length len, into a C string according to the flags.
+   The length of the returned buffer is stored in out_len.
+   Result should be freed with gpr_free() */
+char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags,
+                          size_t* out_len);
 
 /* Parses an array of bytes into an integer (base 10). Returns 1 on success,
    0 on failure. */
index cacf5e8..3755269 100644 (file)
@@ -243,7 +243,7 @@ void Fork::AwaitThreads() {
 
 internal::ExecCtxState* Fork::exec_ctx_state_ = nullptr;
 internal::ThreadState* Fork::thread_state_ = nullptr;
-bool Fork::support_enabled_ = false;
+std::atomic<bool> Fork::support_enabled_;
 bool Fork::override_enabled_ = false;
 Fork::child_postfork_func Fork::reset_child_polling_engine_ = nullptr;
 }  // namespace grpc_core
index 5a7404f..73f2fa5 100644 (file)
 #ifndef GRPC_CORE_LIB_GPRPP_FORK_H
 #define GRPC_CORE_LIB_GPRPP_FORK_H
 
+#include <grpc/support/port_platform.h>
+
+#include <atomic>
+
 /*
  * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
  *       AROUND VERY SPECIFIC USE CASES.
@@ -78,7 +82,7 @@ class Fork {
  private:
   static internal::ExecCtxState* exec_ctx_state_;
   static internal::ThreadState* thread_state_;
-  static bool support_enabled_;
+  static std::atomic<bool> support_enabled_;
   static bool override_enabled_;
   static child_postfork_func reset_child_polling_engine_;
 };
index a1bbf07..ed986b8 100644 (file)
 //
 // Declaring config variables for other modules to access:
 //   GPR_GLOBAL_CONFIG_DECLARE_*TYPE*(name)
+//
+// * Caveat for setting global configs at runtime
+//
+// Setting global configs at runtime multiple times is safe but it doesn't
+// mean that it will have a valid effect on the module depending configs.
+// In unit tests, it may be unpredictable to set different global configs
+// between test cases because grpc init and shutdown can ignore changes.
+// It's considered safe to set global configs before the first call to
+// grpc_init().
 
 // --------------------------------------------------------------------
 // How to customize the global configuration system:
index dd011fb..175677e 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
 #define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
 
-// This is a placeholder for custom global configuration implementaion.
+// This is a placeholder for custom global configuration implementation.
 // To use the custom one, please define following macros here.
 //
 //   GPR_GLOBAL_CONFIG_DEFINE_BOOL
index 66dc751..ffc3738 100644 (file)
@@ -97,6 +97,14 @@ class InlinedVector {
     return data()[offset];
   }
 
+  bool operator==(const InlinedVector& other) const {
+    if (size_ != other.size_) return false;
+    for (size_t i = 0; i < size_; ++i) {
+      if (data()[i] != other.data()[i]) return false;
+    }
+    return true;
+  }
+
   void reserve(size_t capacity) {
     if (capacity > capacity_) {
       T* new_dynamic = static_cast<T*>(gpr_malloc(sizeof(T) * capacity));
index b210c26..36e32d6 100644 (file)
 #include <grpc/support/port_platform.h>
 
 #include <string.h>
+
+#include <algorithm>
 #include <functional>
 #include <iterator>
+
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/pair.h"
@@ -88,6 +91,13 @@ class Map {
 
   iterator end() { return iterator(this, nullptr); }
 
+  iterator lower_bound(const Key& k) {
+    key_compare compare;
+    return std::find_if(begin(), end(), [&k, &compare](const value_type& v) {
+      return !compare(v.first, k);
+    });
+  }
+
  private:
   friend class testing::MapTest;
   struct Entry {
@@ -112,7 +122,10 @@ class Map {
   // inserted entry and the second value being the new root of the subtree
   // after a rebalance
   Pair<iterator, Entry*> InsertRecursive(Entry* root, value_type&& p);
-  static Entry* RemoveRecursive(Entry* root, const key_type& k);
+  // Returns a pair with the first value being an iterator pointing to the
+  // successor of the deleted entry and the second value being the new root of
+  // the subtree after a rebalance
+  Pair<iterator, Entry*> RemoveRecursive(Entry* root, const key_type& k);
   // Return 0 if lhs = rhs
   //        1 if lhs > rhs
   //       -1 if lhs < rhs
@@ -233,10 +246,10 @@ typename Map<Key, T, Compare>::iterator Map<Key, T, Compare>::erase(
     iterator iter) {
   if (iter == end()) return iter;
   key_type& del_key = iter->first;
-  iter++;
-  root_ = RemoveRecursive(root_, del_key);
+  Pair<iterator, Entry*> ret = RemoveRecursive(root_, del_key);
+  root_ = ret.second;
   size_--;
-  return iter;
+  return ret.first;
 }
 
 template <class Key, class T, class Compare>
@@ -373,34 +386,38 @@ Map<Key, T, Compare>::RebalanceTreeAfterDeletion(Entry* root) {
 }
 
 template <class Key, class T, class Compare>
-typename Map<Key, T, Compare>::Entry* Map<Key, T, Compare>::RemoveRecursive(
-    Entry* root, const key_type& k) {
-  if (root == nullptr) return root;
+typename ::grpc_core::Pair<typename Map<Key, T, Compare>::iterator,
+                           typename Map<Key, T, Compare>::Entry*>
+Map<Key, T, Compare>::RemoveRecursive(Entry* root, const key_type& k) {
+  Pair<iterator, Entry*> ret = MakePair(end(), root);
+  if (root == nullptr) return ret;
   int comp = CompareKeys(root->pair.first, k);
   if (comp > 0) {
-    root->left = RemoveRecursive(root->left, k);
+    ret = RemoveRecursive(root->left, k);
+    root->left = ret.second;
   } else if (comp < 0) {
-    root->right = RemoveRecursive(root->right, k);
+    ret = RemoveRecursive(root->right, k);
+    root->right = ret.second;
   } else {
-    Entry* ret;
+    Entry* entry;
+    Entry* successor = InOrderSuccessor(root);
     if (root->left == nullptr) {
-      ret = root->right;
+      entry = root->right;
       Delete(root);
-      return ret;
+      return MakePair(iterator(this, successor), entry);
     } else if (root->right == nullptr) {
-      ret = root->left;
+      entry = root->left;
       Delete(root);
-      return ret;
+      return MakePair(iterator(this, successor), entry);
     } else {
-      ret = root->right;
-      while (ret->left != nullptr) {
-        ret = ret->left;
-      }
-      root->pair.swap(ret->pair);
-      root->right = RemoveRecursive(root->right, ret->pair.first);
+      entry = successor;
+      root->pair.swap(entry->pair);
+      ret = RemoveRecursive(root->right, entry->pair.first);
+      root->right = ret.second;
+      ret.first = iterator(this, root);
     }
   }
-  return RebalanceTreeAfterDeletion(root);
+  return MakePair(ret.first, RebalanceTreeAfterDeletion(root));
 }
 
 template <class Key, class T, class Compare>
index b4b63ae..70ad430 100644 (file)
 
 // Add this to a class that want to use Delete(), but has a private or
 // protected destructor.
-#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \
+#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \
   template <typename T>                           \
   friend void grpc_core::Delete(T*);
 // Add this to a class that want to use New(), but has a private or
 // protected constructor.
-#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \
+#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \
   template <typename T, typename... Args>      \
   friend T* grpc_core::New(Args&&...);
 
index 2e467e4..82350a1 100644 (file)
@@ -84,7 +84,7 @@ class InternallyRefCounted : public Orphanable {
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
   // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
   template <typename T>
index 83e9429..cab1aaa 100644 (file)
@@ -44,7 +44,7 @@ class PolymorphicRefCount {
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
   virtual ~PolymorphicRefCount() = default;
 };
@@ -57,7 +57,7 @@ class NonPolymorphicRefCount {
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
   ~NonPolymorphicRefCount() = default;
 };
@@ -180,7 +180,7 @@ class RefCount {
 // 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
+// (b) you are guaranteed to call Unref only on concrete leaf classes and not
 //     their parents.
 //
 // The following example is illegal, because calling Unref() will not call
@@ -221,6 +221,11 @@ class RefCounted : public Impl {
     }
   }
 
+  bool RefIfNonZero() { return refs_.RefIfNonZero(); }
+  bool RefIfNonZero(const DebugLocation& location, const char* reason) {
+    return refs_.RefIfNonZero(location, reason);
+  }
+
   // Not copyable nor movable.
   RefCounted(const RefCounted&) = delete;
   RefCounted& operator=(const RefCounted&) = delete;
@@ -228,7 +233,7 @@ class RefCounted : public Impl {
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
   // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
   // Note: RefCount tracing is only enabled on debug builds, even when a
index 8a8da8b..93bb143 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/http/format_request.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/endpoint.h"
@@ -112,12 +113,11 @@ static void append_error(internal_request* req, grpc_error* error) {
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request");
   }
   grpc_resolved_address* addr = &req->addresses->addrs[req->next_address - 1];
-  char* addr_text = grpc_sockaddr_to_uri(addr);
+  grpc_core::UniquePtr<char> addr_text(grpc_sockaddr_to_uri(addr));
   req->overall_error = grpc_error_add_child(
       req->overall_error,
       grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
-                         grpc_slice_from_copied_string(addr_text)));
-  gpr_free(addr_text);
+                         grpc_slice_from_moved_string(std::move(addr_text))));
 }
 
 static void do_read(internal_request* req) {
index 8bb2718..755ce02 100644 (file)
@@ -133,7 +133,7 @@ class TracedBuffer {
                        grpc_error* shutdown_err);
 
  private:
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
 
   TracedBuffer(uint32_t seq_no, void* arg)
       : seq_no_(seq_no), arg_(arg), next_(nullptr) {}
index 6a4e85d..6530d1c 100644 (file)
@@ -28,7 +28,7 @@
 
 namespace grpc_core {
 
-TraceFlag grpc_call_combiner_trace(false, "call_combiner");
+DebugOnlyTraceFlag grpc_call_combiner_trace(false, "call_combiner");
 
 namespace {
 
index a10b437..b56966f 100644 (file)
@@ -43,7 +43,7 @@
 
 namespace grpc_core {
 
-extern TraceFlag grpc_call_combiner_trace;
+extern DebugOnlyTraceFlag grpc_call_combiner_trace;
 
 class CallCombiner {
  public:
index 2fda160..8d01386 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <grpc/support/port_platform.h>
 
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_CFSTREAM
@@ -47,7 +48,7 @@ void CFStreamHandle::Release(void* info) {
 
 CFStreamHandle* CFStreamHandle::CreateStreamHandle(
     CFReadStreamRef read_stream, CFWriteStreamRef write_stream) {
-  return new CFStreamHandle(read_stream, write_stream);
+  return grpc_core::New<CFStreamHandle>(read_stream, write_stream);
 }
 
 void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
@@ -188,7 +189,7 @@ void CFStreamHandle::Unref(const char* file, int line, const char* reason) {
             reason, val, val - 1);
   }
   if (gpr_unref(&refcount_)) {
-    delete this;
+    grpc_core::Delete<CFStreamHandle>(this);
   }
 }
 
index 4f4d159..05f45ed 100644 (file)
@@ -29,6 +29,7 @@
 #ifdef GRPC_CFSTREAM
 #import <CoreFoundation/CoreFoundation.h>
 
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/lockfree_event.h"
 
@@ -65,6 +66,9 @@ class CFStreamHandle final {
   dispatch_queue_t dispatch_queue_;
 
   gpr_refcount refcount_;
+
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 };
 
 #ifdef DEBUG
index f194eb6..ebec9dc 100644 (file)
@@ -795,9 +795,9 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
 }
 #endif
 
-bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
-                       int line) {
-  if (error == GRPC_ERROR_NONE) return true;
+bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+                    int line) {
+  GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
   const char* msg = grpc_error_string(error);
   gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
   GRPC_ERROR_UNREF(error);
index 7b04888..0a72e5c 100644 (file)
@@ -261,9 +261,15 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
 #define GRPC_WSA_ERROR(err, call_name) \
   grpc_wsa_error(__FILE__, __LINE__, err, call_name)
 
-bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
-                       int line);
+bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+                    int line);
+inline bool grpc_log_if_error(const char* what, grpc_error* error,
+                              const char* file, int line) {
+  return error == GRPC_ERROR_NONE ? true
+                                  : grpc_log_error(what, error, file, line);
+}
+
 #define GRPC_LOG_IF_ERROR(what, error) \
-  grpc_log_if_error((what), (error), __FILE__, __LINE__)
+  (grpc_log_if_error((what), (error), __FILE__, __LINE__))
 
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */
index 8027396..7b0cbd6 100644 (file)
@@ -49,7 +49,7 @@ struct grpc_error {
   uint8_t strs[GRPC_ERROR_STR_MAX];
   uint8_t times[GRPC_ERROR_TIME_MAX];
   // The child errors are stored in the arena, but are effectively a linked list
-  // structure, since they are contained withing grpc_linked_error objects.
+  // structure, since they are contained within grpc_linked_error objects.
   uint8_t first_err;
   uint8_t last_err;
   // The arena is dynamically reallocated with a grow factor of 1.5.
index cacf7f9..0c357dd 100644 (file)
@@ -1031,7 +1031,7 @@ static grpc_error* pollset_work(grpc_pollset* ps,
        process the pending epoll events.
 
        The reason for decoupling do_epoll_wait and process_epoll_events is to
-       better distrubute the work (i.e handling epoll events) across multiple
+       better distribute the work (i.e handling epoll events) across multiple
        threads
 
        process_epoll_events() returns very quickly: It just queues the work on
index ddafb7b..92f81c2 100644 (file)
@@ -44,11 +44,11 @@ GPR_GLOBAL_CONFIG_DEFINE_STRING(
     "This is a comma-separated list of engines, which are tried in priority "
     "order first -> last.")
 
-grpc_core::TraceFlag grpc_polling_trace(false,
-                                        "polling"); /* Disabled by default */
+grpc_core::DebugOnlyTraceFlag grpc_polling_trace(
+    false, "polling"); /* Disabled by default */
 
 /* Traces fd create/close operations */
-grpc_core::TraceFlag grpc_fd_trace(false, "fd_trace");
+grpc_core::DebugOnlyTraceFlag grpc_fd_trace(false, "fd_trace");
 grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
 grpc_core::DebugOnlyTraceFlag grpc_polling_api_trace(false, "polling_api");
 
index 30bb5e4..84edabc 100644 (file)
@@ -32,8 +32,9 @@
 
 GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_poll_strategy);
 
-extern grpc_core::TraceFlag grpc_fd_trace;      /* Disabled by default */
-extern grpc_core::TraceFlag grpc_polling_trace; /* Disabled by default */
+extern grpc_core::DebugOnlyTraceFlag grpc_fd_trace; /* Disabled by default */
+extern grpc_core::DebugOnlyTraceFlag
+    grpc_polling_trace; /* Disabled by default */
 
 #define GRPC_FD_TRACE(format, ...)                        \
   if (GRPC_TRACE_FLAG_ENABLED(grpc_fd_trace)) {           \
index 32c62b7..e3f5715 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "src/core/lib/debug/trace.h"
 
-grpc_core::TraceFlag grpc_polling_trace(false,
-                                        "polling"); /* Disabled by default */
+grpc_core::DebugOnlyTraceFlag grpc_polling_trace(
+    false, "polling"); /* Disabled by default */
 
 #endif  // GRPC_WINSOCK_SOCKET
index b86aa6f..802e3bd 100644 (file)
@@ -49,6 +49,7 @@ static gpr_mu g_mu;
 static gpr_cv g_rcv;
 static int g_shutdown;
 static grpc_iomgr_object g_root_object;
+static bool g_grpc_abort_on_leaks;
 
 void grpc_iomgr_init() {
   grpc_core::ExecCtx exec_ctx;
@@ -57,11 +58,12 @@ void grpc_iomgr_init() {
   gpr_mu_init(&g_mu);
   gpr_cv_init(&g_rcv);
   grpc_core::Executor::InitAll();
-  grpc_timer_list_init();
   g_root_object.next = g_root_object.prev = &g_root_object;
   g_root_object.name = (char*)"root";
   grpc_iomgr_platform_init();
+  grpc_timer_list_init();
   grpc_core::grpc_errqueue_init();
+  g_grpc_abort_on_leaks = GPR_GLOBAL_CONFIG_GET(grpc_abort_on_leaks);
 }
 
 void grpc_iomgr_start() { grpc_timer_manager_init(); }
@@ -189,6 +191,4 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object* obj) {
   gpr_free(obj->name);
 }
 
-bool grpc_iomgr_abort_on_leaks(void) {
-  return GPR_GLOBAL_CONFIG_GET(grpc_abort_on_leaks);
-}
+bool grpc_iomgr_abort_on_leaks(void) { return g_grpc_abort_on_leaks; }
index f0c40b4..f33485e 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "src/core/lib/debug/trace.h"
 
-extern grpc_core::TraceFlag grpc_polling_trace;
+extern grpc_core::DebugOnlyTraceFlag grpc_polling_trace;
 
 /* 'state' holds the to call when the fd is readable or writable respectively.
    It can contain one of the following values:
index 605692a..63a0269 100644 (file)
 #define GRPC_CUSTOM_SOCKET
 #endif
 #endif
+/* This needs to be separate from the other conditions because it needs to
+ * apply to custom sockets too */
+#ifdef GPR_WINDOWS
+#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1
+#endif
 #if defined(GRPC_CUSTOM_SOCKET)
 // Do Nothing
 #elif defined(GPR_MANYLINUX1)
@@ -45,7 +50,6 @@
 #define GRPC_WINSOCK_SOCKET 1
 #define GRPC_WINDOWS_SOCKETUTILS 1
 #define GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER 1
-#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1
 #elif defined(GPR_ANDROID)
 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
 #define GRPC_HAVE_IP_PKTINFO 1
index b9376b3..889272f 100644 (file)
@@ -685,7 +685,6 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
     uint32_t opt = grpc_core::kTimestampingSocketOptions;
     if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING,
                    static_cast<void*>(&opt), sizeof(opt)) != 0) {
-      grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
       if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
         gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket.");
       }
@@ -980,8 +979,7 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
         // unref all and forget about all slices that have been written to this
         // point
         for (size_t idx = 0; idx < unwind_slice_idx; ++idx) {
-          grpc_slice_unref_internal(
-              grpc_slice_buffer_take_first(tcp->outgoing_buffer));
+          grpc_slice_buffer_remove_first(tcp->outgoing_buffer);
         }
         return false;
       } else if (errno == EPIPE) {
index ea745f2..f2e4b1b 100644 (file)
@@ -41,6 +41,11 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
   return grpc_tcp_server_impl->add_port(s, addr, out_port);
 }
 
+grpc_core::TcpServerFdHandler* grpc_tcp_server_create_fd_handler(
+    grpc_tcp_server* s) {
+  return grpc_tcp_server_impl->create_fd_handler(s);
+}
+
 unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
                                        unsigned port_index) {
   return grpc_tcp_server_impl->port_fd_count(s, port_index);
index 8fcbb2f..0d16b66 100644 (file)
@@ -22,7 +22,9 @@
 #include <grpc/support/port_platform.h>
 
 #include <grpc/grpc.h>
+#include <grpc/impl/codegen/grpc_types.h>
 
+#include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -37,6 +39,10 @@ typedef struct grpc_tcp_server_acceptor {
   /* Indices that may be passed to grpc_tcp_server_port_fd(). */
   unsigned port_index;
   unsigned fd_index;
+  /* Data when the connection is passed to tcp_server from external. */
+  bool external_connection;
+  int listener_fd;
+  grpc_byte_buffer* pending_data;
 } grpc_tcp_server_acceptor;
 
 /* Called for newly connected TCP connections.
@@ -44,6 +50,18 @@ typedef struct grpc_tcp_server_acceptor {
 typedef void (*grpc_tcp_server_cb)(void* arg, grpc_endpoint* ep,
                                    grpc_pollset* accepting_pollset,
                                    grpc_tcp_server_acceptor* acceptor);
+namespace grpc_core {
+// An interface for a handler to take a externally connected fd as a internal
+// connection.
+class TcpServerFdHandler {
+ public:
+  virtual ~TcpServerFdHandler() = default;
+  virtual void Handle(int listener_fd, int fd,
+                      grpc_byte_buffer* pending_read) GRPC_ABSTRACT;
+
+  GRPC_ABSTRACT_BASE_CLASS;
+};
+}  // namespace grpc_core
 
 typedef struct grpc_tcp_server_vtable {
   grpc_error* (*create)(grpc_closure* shutdown_complete,
@@ -54,6 +72,7 @@ typedef struct grpc_tcp_server_vtable {
                 void* cb_arg);
   grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr,
                           int* out_port);
+  grpc_core::TcpServerFdHandler* (*create_fd_handler)(grpc_tcp_server* s);
   unsigned (*port_fd_count)(grpc_tcp_server* s, unsigned port_index);
   int (*port_fd)(grpc_tcp_server* s, unsigned port_index, unsigned fd_index);
   grpc_tcp_server* (*ref)(grpc_tcp_server* s);
@@ -88,6 +107,11 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
                                      const grpc_resolved_address* addr,
                                      int* out_port);
 
+/* Create and return a TcpServerFdHandler so that it can be used by upper layer
+   to hand over an externally connected fd to the grpc server. */
+grpc_core::TcpServerFdHandler* grpc_tcp_server_create_fd_handler(
+    grpc_tcp_server* s);
+
 /* Number of fds at the given port_index, or 0 if port_index is out of
    bounds. */
 unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s, unsigned port_index);
index 133847d..767404b 100644 (file)
@@ -233,6 +233,7 @@ static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) {
   acceptor->from_server = sp->server;
   acceptor->port_index = sp->port_index;
   acceptor->fd_index = 0;
+  acceptor->external_connection = false;
   sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, nullptr, acceptor);
   gpr_free(peer_name_string);
 }
@@ -456,16 +457,17 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
   }
 }
 
+static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler(
+    grpc_tcp_server* s) {
+  return nullptr;
+}
+
 grpc_tcp_server_vtable custom_tcp_server_vtable = {
-    tcp_server_create,
-    tcp_server_start,
-    tcp_server_add_port,
-    tcp_server_port_fd_count,
-    tcp_server_port_fd,
-    tcp_server_ref,
-    tcp_server_shutdown_starting_add,
-    tcp_server_unref,
-    tcp_server_shutdown_listeners};
+    tcp_server_create,        tcp_server_start,
+    tcp_server_add_port,      tcp_server_create_fd_handler,
+    tcp_server_port_fd_count, tcp_server_port_fd,
+    tcp_server_ref,           tcp_server_shutdown_starting_add,
+    tcp_server_unref,         tcp_server_shutdown_listeners};
 
 #ifdef GRPC_UV_TEST
 grpc_tcp_server_vtable* default_tcp_server_vtable = &custom_tcp_server_vtable;
index 0133972..689c005 100644 (file)
@@ -27,8 +27,6 @@
 
 #ifdef GRPC_POSIX_SOCKET_TCP_SERVER
 
-#include "src/core/lib/iomgr/tcp_server.h"
-
 #include <errno.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
@@ -96,6 +97,7 @@ static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
   s->tail = nullptr;
   s->nports = 0;
   s->channel_args = grpc_channel_args_copy(args);
+  s->fd_handler = nullptr;
   gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
   *server = s;
   return GRPC_ERROR_NONE;
@@ -117,6 +119,7 @@ static void finish_shutdown(grpc_tcp_server* s) {
     gpr_free(sp);
   }
   grpc_channel_args_destroy(s->channel_args);
+  grpc_core::Delete(s->fd_handler);
 
   gpr_free(s);
 }
@@ -254,6 +257,7 @@ static void on_read(void* arg, grpc_error* err) {
     acceptor->from_server = sp->server;
     acceptor->port_index = sp->port_index;
     acceptor->fd_index = sp->fd_index;
+    acceptor->external_connection = false;
 
     sp->server->on_accept_cb(
         sp->server->on_accept_cb_arg,
@@ -562,14 +566,71 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
   gpr_mu_unlock(&s->mu);
 }
 
+namespace {
+class ExternalConnectionHandler : public grpc_core::TcpServerFdHandler {
+ public:
+  explicit ExternalConnectionHandler(grpc_tcp_server* s) : s_(s) {}
+
+  // TODO(yangg) resolve duplicate code with on_read
+  void Handle(int listener_fd, int fd, grpc_byte_buffer* buf) override {
+    grpc_pollset* read_notifier_pollset;
+    grpc_resolved_address addr;
+    char* addr_str;
+    char* name;
+    memset(&addr, 0, sizeof(addr));
+    addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
+    grpc_core::ExecCtx exec_ctx;
+
+    if (getpeername(fd, reinterpret_cast<struct sockaddr*>(addr.addr),
+                    &(addr.len)) < 0) {
+      gpr_log(GPR_ERROR, "Failed getpeername: %s", strerror(errno));
+      close(fd);
+      return;
+    }
+    grpc_set_socket_no_sigpipe_if_possible(fd);
+    addr_str = grpc_sockaddr_to_uri(&addr);
+    gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
+    if (grpc_tcp_trace.enabled()) {
+      gpr_log(GPR_INFO, "SERVER_CONNECT: incoming external connection: %s",
+              addr_str);
+    }
+    grpc_fd* fdobj = grpc_fd_create(fd, name, true);
+    read_notifier_pollset =
+        s_->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add(
+                         &s_->next_pollset_to_assign, 1)) %
+                     s_->pollset_count];
+    grpc_pollset_add_fd(read_notifier_pollset, fdobj);
+    grpc_tcp_server_acceptor* acceptor =
+        static_cast<grpc_tcp_server_acceptor*>(gpr_malloc(sizeof(*acceptor)));
+    acceptor->from_server = s_;
+    acceptor->port_index = -1;
+    acceptor->fd_index = -1;
+    acceptor->external_connection = true;
+    acceptor->listener_fd = listener_fd;
+    acceptor->pending_data = buf;
+    s_->on_accept_cb(s_->on_accept_cb_arg,
+                     grpc_tcp_create(fdobj, s_->channel_args, addr_str),
+                     read_notifier_pollset, acceptor);
+    gpr_free(name);
+    gpr_free(addr_str);
+  }
+
+ private:
+  grpc_tcp_server* s_;
+};
+}  // namespace
+
+static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler(
+    grpc_tcp_server* s) {
+  s->fd_handler = grpc_core::New<ExternalConnectionHandler>(s);
+  return s->fd_handler;
+}
+
 grpc_tcp_server_vtable grpc_posix_tcp_server_vtable = {
-    tcp_server_create,
-    tcp_server_start,
-    tcp_server_add_port,
-    tcp_server_port_fd_count,
-    tcp_server_port_fd,
-    tcp_server_ref,
-    tcp_server_shutdown_starting_add,
-    tcp_server_unref,
-    tcp_server_shutdown_listeners};
+    tcp_server_create,        tcp_server_start,
+    tcp_server_add_port,      tcp_server_create_fd_handler,
+    tcp_server_port_fd_count, tcp_server_port_fd,
+    tcp_server_ref,           tcp_server_shutdown_starting_add,
+    tcp_server_unref,         tcp_server_shutdown_listeners};
+
 #endif /* GRPC_POSIX_SOCKET_TCP_SERVER */
index dd19909..390d6d2 100644 (file)
@@ -92,6 +92,9 @@ struct grpc_tcp_server {
 
   /* channel args for this server */
   grpc_channel_args* channel_args;
+
+  /* a handler for external connections, owned */
+  grpc_core::TcpServerFdHandler* fd_handler;
 };
 
 /* If successful, add a listener to \a s for \a addr, set \a dsmode for the
index 7ac4234..abfa3be 100644 (file)
@@ -372,6 +372,7 @@ static void on_accept(void* arg, grpc_error* error) {
     acceptor->from_server = sp->server;
     acceptor->port_index = sp->port_index;
     acceptor->fd_index = 0;
+    acceptor->external_connection = false;
     sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, NULL, acceptor);
   }
   /* As we were notified from the IOCP of one and exactly one accept,
@@ -545,16 +546,17 @@ static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
   return -1;
 }
 
+static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler(
+    grpc_tcp_server* s) {
+  return nullptr;
+}
+
 static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
 
 grpc_tcp_server_vtable grpc_windows_tcp_server_vtable = {
-    tcp_server_create,
-    tcp_server_start,
-    tcp_server_add_port,
-    tcp_server_port_fd_count,
-    tcp_server_port_fd,
-    tcp_server_ref,
-    tcp_server_shutdown_starting_add,
-    tcp_server_unref,
-    tcp_server_shutdown_listeners};
+    tcp_server_create,        tcp_server_start,
+    tcp_server_add_port,      tcp_server_create_fd_handler,
+    tcp_server_port_fd_count, tcp_server_port_fd,
+    tcp_server_ref,           tcp_server_shutdown_starting_add,
+    tcp_server_unref,         tcp_server_shutdown_listeners};
 #endif /* GRPC_WINSOCK_SOCKET */
index e53ff47..f0847a1 100644 (file)
@@ -53,7 +53,7 @@ typedef struct uv_socket_t {
   char* read_buf;
   size_t read_len;
 
-  bool pending_connection;
+  int pending_connections;
   grpc_custom_socket* accept_socket;
   grpc_error* accept_error;
 
@@ -206,7 +206,7 @@ static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
   // Node uses a garbage collector to call destructors, so we don't
   // want to hold the uv loop open with active gRPC objects.
   uv_unref((uv_handle_t*)uv_socket->handle);
-  uv_socket->pending_connection = false;
+  uv_socket->pending_connections = 0;
   uv_socket->accept_socket = nullptr;
   uv_socket->accept_error = GRPC_ERROR_NONE;
   return GRPC_ERROR_NONE;
@@ -243,14 +243,14 @@ static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
 
 static void accept_new_connection(grpc_custom_socket* socket) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
-  if (!uv_socket->pending_connection || !uv_socket->accept_socket) {
+  if (uv_socket->pending_connections == 0 || !uv_socket->accept_socket) {
     return;
   }
   grpc_custom_socket* new_socket = uv_socket->accept_socket;
   grpc_error* error = uv_socket->accept_error;
   uv_socket->accept_socket = nullptr;
   uv_socket->accept_error = GRPC_ERROR_NONE;
-  uv_socket->pending_connection = false;
+  uv_socket->pending_connections -= 1;
   if (uv_socket->accept_error != GRPC_ERROR_NONE) {
     uv_stream_t dummy_handle;
     uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle);
@@ -270,8 +270,6 @@ static void accept_new_connection(grpc_custom_socket* socket) {
 static void uv_on_connect(uv_stream_t* server, int status) {
   grpc_custom_socket* socket = (grpc_custom_socket*)server->data;
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
-  GPR_ASSERT(!uv_socket->pending_connection);
-  uv_socket->pending_connection = true;
   if (status < 0) {
     switch (status) {
       case UV_EINTR:
@@ -281,6 +279,7 @@ static void uv_on_connect(uv_stream_t* server, int status) {
         uv_socket->accept_error = tcp_error_create("accept failed", status);
     }
   }
+  uv_socket->pending_connections += 1;
   accept_new_connection(socket);
 }
 
index 17e933b..11da149 100644 (file)
@@ -29,7 +29,8 @@
 
 typedef struct grpc_timer {
   grpc_millis deadline;
-  uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
+  // Uninitialized if not using heap, or INVALID_HEAP_INDEX if not in heap.
+  uint32_t heap_index;
   bool pending;
   struct grpc_timer* next;
   struct grpc_timer* prev;
index 5f8865c..3e85394 100644 (file)
@@ -332,7 +332,7 @@ void GrpcUdpListener::OnFdAboutToOrphan() {
   GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_,
                     grpc_schedule_on_exec_ctx);
   if (!orphan_notified_ && udp_handler_ != nullptr) {
-    /* Singals udp_handler that the FD is about to be closed and
+    /* Signals udp_handler that the FD is about to be closed and
      * should no longer be used. */
     GRPC_CLOSURE_INIT(&orphan_fd_closure_, shutdown_fd, this,
                       grpc_schedule_on_exec_ctx);
@@ -645,7 +645,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
           grpc_sockaddr_set_port(addr, allocated_port1);
           port = allocated_port1;
         } else if (allocated_port1 >= 0) {
-          /* The following sucessfully created socket should have same port as
+          /* The following successfully created socket should have same port as
            * the first one. */
           GPR_ASSERT(port == allocated_port1);
         }
index 333366d..92af88a 100644 (file)
@@ -85,7 +85,7 @@ static grpc_error* process_plugin_result(
                              grpc_validate_header_key_is_legal(md[i].key))) {
         seen_illegal_header = true;
         break;
-      } else if (!grpc_is_binary_header(md[i].key) &&
+      } else if (!grpc_is_binary_header_internal(md[i].key) &&
                  !GRPC_LOG_IF_ERROR(
                      "validate_metadata_from_plugin",
                      grpc_validate_header_nonbin_value_is_legal(md[i].value))) {
index 83db86f..65e57ce 100644 (file)
@@ -46,7 +46,7 @@ void grpc_tsi_ssl_pem_key_cert_pairs_destroy(tsi_ssl_pem_key_cert_pair* kp,
 
 grpc_ssl_credentials::grpc_ssl_credentials(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-    const verify_peer_options* verify_options)
+    const grpc_ssl_verify_peer_options* verify_options)
     : grpc_channel_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_SSL) {
   build_config(pem_root_certs, pem_key_cert_pair, verify_options);
 }
@@ -94,7 +94,7 @@ grpc_ssl_credentials::create_security_connector(
 
 void grpc_ssl_credentials::build_config(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-    const verify_peer_options* verify_options) {
+    const grpc_ssl_verify_peer_options* verify_options) {
   config_.pem_root_certs = gpr_strdup(pem_root_certs);
   if (pem_key_cert_pair != nullptr) {
     GPR_ASSERT(pem_key_cert_pair->private_key != nullptr);
@@ -117,6 +117,8 @@ void grpc_ssl_credentials::build_config(
   }
 }
 
+/* Deprecated in favor of grpc_ssl_credentials_create_ex. Will be removed
+ * once all of its call sites are migrated to grpc_ssl_credentials_create_ex. */
 grpc_channel_credentials* grpc_ssl_credentials_create(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
     const verify_peer_options* verify_options, void* reserved) {
@@ -128,6 +130,22 @@ grpc_channel_credentials* grpc_ssl_credentials_create(
       4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved));
   GPR_ASSERT(reserved == nullptr);
 
+  return grpc_core::New<grpc_ssl_credentials>(
+      pem_root_certs, pem_key_cert_pair,
+      reinterpret_cast<const grpc_ssl_verify_peer_options*>(verify_options));
+}
+
+grpc_channel_credentials* grpc_ssl_credentials_create_ex(
+    const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
+    const grpc_ssl_verify_peer_options* verify_options, void* reserved) {
+  GRPC_API_TRACE(
+      "grpc_ssl_credentials_create(pem_root_certs=%s, "
+      "pem_key_cert_pair=%p, "
+      "verify_options=%p, "
+      "reserved=%p)",
+      4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved));
+  GPR_ASSERT(reserved == nullptr);
+
   return grpc_core::New<grpc_ssl_credentials>(pem_root_certs, pem_key_cert_pair,
                                               verify_options);
 }
index e117432..545a27f 100644 (file)
@@ -28,7 +28,7 @@ class grpc_ssl_credentials : public grpc_channel_credentials {
  public:
   grpc_ssl_credentials(const char* pem_root_certs,
                        grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-                       const verify_peer_options* verify_options);
+                       const grpc_ssl_verify_peer_options* verify_options);
 
   ~grpc_ssl_credentials() override;
 
@@ -41,7 +41,7 @@ class grpc_ssl_credentials : public grpc_channel_credentials {
  private:
   void build_config(const char* pem_root_certs,
                     grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-                    const verify_peer_options* verify_options);
+                    const grpc_ssl_verify_peer_options* verify_options);
 
   grpc_ssl_config config_;
 };
index 4c74c5c..f71ee54 100644 (file)
@@ -102,7 +102,7 @@ class grpc_channel_security_connector : public grpc_security_connector {
                                grpc_auth_context* auth_context,
                                grpc_closure* on_call_host_checked,
                                grpc_error** error) GRPC_ABSTRACT;
-  /// Cancels a pending asychronous call to
+  /// Cancels a pending asynchronous call to
   /// grpc_channel_security_connector_check_call_host() with
   /// \a on_call_host_checked as its callback.
   virtual void cancel_check_call_host(grpc_closure* on_call_host_checked,
index e76f4f1..f920dc6 100644 (file)
@@ -310,7 +310,7 @@ class grpc_ssl_server_security_connector
  private:
   /* Attempts to fetch the server certificate config if a callback is available.
    * Current certificate config will continue to be used if the callback returns
-   * an error. Returns true if new credentials were sucessfully loaded. */
+   * an error. Returns true if new credentials were successfully loaded. */
   bool try_fetch_ssl_server_credentials() {
     grpc_ssl_server_certificate_config* certificate_config = nullptr;
     bool status;
index 16a8e58..5e73c21 100644 (file)
@@ -32,6 +32,9 @@ void grpc_auth_metadata_context_build(
     const grpc_slice& call_method, grpc_auth_context* auth_context,
     grpc_auth_metadata_context* auth_md_context);
 
+void grpc_auth_metadata_context_copy(grpc_auth_metadata_context* from,
+                                     grpc_auth_metadata_context* to);
+
 void grpc_auth_metadata_context_reset(grpc_auth_metadata_context* context);
 
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_AUTH_FILTERS_H */
index 0c40dd7..1062fc2 100644 (file)
@@ -112,6 +112,19 @@ struct call_data {
 
 }  // namespace
 
+void grpc_auth_metadata_context_copy(grpc_auth_metadata_context* from,
+                                     grpc_auth_metadata_context* to) {
+  grpc_auth_metadata_context_reset(to);
+  to->channel_auth_context = from->channel_auth_context;
+  if (to->channel_auth_context != nullptr) {
+    const_cast<grpc_auth_context*>(to->channel_auth_context)
+        ->Ref(DEBUG_LOCATION, "grpc_auth_metadata_context_copy")
+        .release();
+  }
+  to->service_url = gpr_strdup(from->service_url);
+  to->method_name = gpr_strdup(from->method_name);
+}
+
 void grpc_auth_metadata_context_reset(
     grpc_auth_metadata_context* auth_md_context) {
   if (auth_md_context->service_url != nullptr) {
index 3605bbe..3ad0477 100644 (file)
@@ -144,11 +144,11 @@ size_t SecurityHandshaker::MoveReadBufferIntoHandshakeBuffer() {
   }
   size_t offset = 0;
   while (args_->read_buffer->count > 0) {
-    grpc_slice next_slice = grpc_slice_buffer_take_first(args_->read_buffer);
-    memcpy(handshake_buffer_ + offset, GRPC_SLICE_START_PTR(next_slice),
-           GRPC_SLICE_LENGTH(next_slice));
-    offset += GRPC_SLICE_LENGTH(next_slice);
-    grpc_slice_unref_internal(next_slice);
+    grpc_slice* next_slice = grpc_slice_buffer_peek_first(args_->read_buffer);
+    memcpy(handshake_buffer_ + offset, GRPC_SLICE_START_PTR(*next_slice),
+           GRPC_SLICE_LENGTH(*next_slice));
+    offset += GRPC_SLICE_LENGTH(*next_slice);
+    grpc_slice_buffer_remove_first(args_->read_buffer);
   }
   return bytes_in_read_buffer;
 }
@@ -195,7 +195,7 @@ void SecurityHandshaker::HandshakeFailedLocked(grpc_error* error) {
 void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
   MutexLock lock(&mu_);
   if (error != GRPC_ERROR_NONE || is_shutdown_) {
-    HandshakeFailedLocked(GRPC_ERROR_REF(error));
+    HandshakeFailedLocked(error);
     return;
   }
   // Create zero-copy frame protector, if implemented.
@@ -255,7 +255,7 @@ void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
 
 void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error* error) {
   RefCountedPtr<SecurityHandshaker>(static_cast<SecurityHandshaker*>(arg))
-      ->OnPeerCheckedInner(error);
+      ->OnPeerCheckedInner(GRPC_ERROR_REF(error));
 }
 
 grpc_error* SecurityHandshaker::CheckPeerLocked() {
index 4475568..88b880a 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <grpc/slice.h>
 
-/* Encodes data using base64. It is the caller's responsability to free
+/* Encodes data using base64. It is the caller's responsibility to free
    the returned char * using gpr_free. Returns NULL on NULL input.
    TODO(makdharma) : change the flags to bool from int */
 char* grpc_base64_encode(const void* data, size_t data_size, int url_safe,
@@ -35,7 +35,7 @@ size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe,
                                          int multiline);
 
 /* Encodes data using base64 and write it to memory pointed to by result. It is
- * the caller's responsiblity to allocate enough memory in |result| to fit the
+ * the caller's responsibility to allocate enough memory in |result| to fit the
  * encoded data. */
 void grpc_base64_encode_core(char* result, const void* vdata, size_t data_size,
                              int url_safe, int multiline);
index 2bf2b0f..eebf66b 100644 (file)
@@ -68,7 +68,8 @@ void grpc_slice_unref(grpc_slice slice) {
 
 /* grpc_slice_from_static_string support structure - a refcount that does
    nothing */
-static grpc_slice_refcount NoopRefcount;
+static grpc_slice_refcount NoopRefcount =
+    grpc_slice_refcount(grpc_slice_refcount::Type::NOP);
 
 size_t grpc_slice_memory_usage(grpc_slice s) {
   if (s.refcount == nullptr || s.refcount == &NoopRefcount) {
@@ -101,18 +102,19 @@ class NewSliceRefcount {
   }
 
   NewSliceRefcount(void (*destroy)(void*), void* user_data)
-      : rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
+      : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
+              &base_),
         user_destroy_(destroy),
         user_data_(user_data) {}
 
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
-  grpc_slice_refcount* base_refcount() { return &rc_; }
+  grpc_slice_refcount* base_refcount() { return &base_; }
 
  private:
   ~NewSliceRefcount() { user_destroy_(user_data_); }
 
-  grpc_slice_refcount rc_;
+  grpc_slice_refcount base_;
   RefCount refs_;
   void (*user_destroy_)(void*);
   void* user_data_;
@@ -140,7 +142,6 @@ grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
 namespace grpc_core {
 /* grpc_slice_new_with_len support structures - we create a refcount object
    extended with the user provided data pointer & destroy function */
-
 class NewWithLenSliceRefcount {
  public:
   static void Destroy(void* arg) {
@@ -149,25 +150,48 @@ class NewWithLenSliceRefcount {
 
   NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
                           size_t user_length)
-      : rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
+      : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
+              &base_),
         user_data_(user_data),
         user_length_(user_length),
         user_destroy_(destroy) {}
 
-  GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
 
-  grpc_slice_refcount* base_refcount() { return &rc_; }
+  grpc_slice_refcount* base_refcount() { return &base_; }
 
  private:
   ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
 
-  grpc_slice_refcount rc_;
+  grpc_slice_refcount base_;
   RefCount refs_;
   void* user_data_;
   size_t user_length_;
   void (*user_destroy_)(void*, size_t);
 };
 
+/** grpc_slice_from_moved_(string|buffer) ref count .*/
+class MovedStringSliceRefCount {
+ public:
+  MovedStringSliceRefCount(grpc_core::UniquePtr<char>&& str)
+      : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
+              &base_),
+        str_(std::move(str)) {}
+
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+  grpc_slice_refcount* base_refcount() { return &base_; }
+
+ private:
+  static void Destroy(void* arg) {
+    Delete(static_cast<MovedStringSliceRefCount*>(arg));
+  }
+
+  grpc_slice_refcount base_;
+  grpc_core::RefCount refs_;
+  grpc_core::UniquePtr<char> str_;
+};
+
 }  // namespace grpc_core
 
 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
@@ -192,6 +216,29 @@ grpc_slice grpc_slice_from_copied_string(const char* source) {
   return grpc_slice_from_copied_buffer(source, strlen(source));
 }
 
+grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
+                                        size_t len) {
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
+  grpc_slice slice;
+  if (len <= sizeof(slice.data.inlined.bytes)) {
+    slice.refcount = nullptr;
+    slice.data.inlined.length = len;
+    memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
+  } else {
+    slice.refcount =
+        grpc_core::New<grpc_core::MovedStringSliceRefCount>(std::move(p))
+            ->base_refcount();
+    slice.data.refcounted.bytes = ptr;
+    slice.data.refcounted.length = len;
+  }
+  return slice;
+}
+
+grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
+  const size_t len = strlen(p.get());
+  return grpc_slice_from_moved_buffer(std::move(p), len);
+}
+
 namespace {
 
 class MallocRefCount {
@@ -410,6 +457,31 @@ int grpc_slice_eq(grpc_slice a, grpc_slice b) {
   return grpc_slice_default_eq_impl(a, b);
 }
 
+int grpc_slice_differs_refcounted(const grpc_slice& a,
+                                  const grpc_slice& b_not_inline) {
+  size_t a_len;
+  const uint8_t* a_ptr;
+  if (a.refcount) {
+    a_len = a.data.refcounted.length;
+    a_ptr = a.data.refcounted.bytes;
+  } else {
+    a_len = a.data.inlined.length;
+    a_ptr = &a.data.inlined.bytes[0];
+  }
+  if (a_len != b_not_inline.data.refcounted.length) {
+    return true;
+  }
+  if (a_len == 0) {
+    return false;
+  }
+  // This check *must* occur after the a_len == 0 check
+  // to retain compatibility with grpc_slice_eq.
+  if (a_ptr == nullptr) {
+    return true;
+  }
+  return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
+}
+
 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
   int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
   if (d != 0) return d;
index 111d3c9..2b69f57 100644 (file)
 /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
 #define GROW(x) (3 * (x) / 2)
 
+/* Typically, we do not actually need to embiggen (by calling
+ * memmove/malloc/realloc) - only if we were up against the full capacity of the
+ * slice buffer. If do_embiggen is inlined, the compiler clobbers multiple
+ * registers pointlessly in the common case. */
+static void GPR_ATTRIBUTE_NOINLINE do_embiggen(grpc_slice_buffer* sb,
+                                               const size_t slice_count,
+                                               const size_t slice_offset) {
+  if (slice_offset != 0) {
+    /* Make room by moving elements if there's still space unused */
+    memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
+    sb->slices = sb->base_slices;
+  } else {
+    /* Allocate more memory if no more space is available */
+    const size_t new_capacity = GROW(sb->capacity);
+    sb->capacity = new_capacity;
+    if (sb->base_slices == sb->inlined) {
+      sb->base_slices = static_cast<grpc_slice*>(
+          gpr_malloc(new_capacity * sizeof(grpc_slice)));
+      memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
+    } else {
+      sb->base_slices = static_cast<grpc_slice*>(
+          gpr_realloc(sb->base_slices, new_capacity * sizeof(grpc_slice)));
+    }
+
+    sb->slices = sb->base_slices + slice_offset;
+  }
+}
+
 static void maybe_embiggen(grpc_slice_buffer* sb) {
   if (sb->count == 0) {
     sb->slices = sb->base_slices;
+    return;
   }
 
   /* How far away from sb->base_slices is sb->slices pointer */
   size_t slice_offset = static_cast<size_t>(sb->slices - sb->base_slices);
   size_t slice_count = sb->count + slice_offset;
-
-  if (slice_count == sb->capacity) {
-    if (sb->base_slices != sb->slices) {
-      /* Make room by moving elements if there's still space unused */
-      memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
-      sb->slices = sb->base_slices;
-    } else {
-      /* Allocate more memory if no more space is available */
-      sb->capacity = GROW(sb->capacity);
-      GPR_ASSERT(sb->capacity > slice_count);
-      if (sb->base_slices == sb->inlined) {
-        sb->base_slices = static_cast<grpc_slice*>(
-            gpr_malloc(sb->capacity * sizeof(grpc_slice)));
-        memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
-      } else {
-        sb->base_slices = static_cast<grpc_slice*>(
-            gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice)));
-      }
-
-      sb->slices = sb->base_slices + slice_offset;
-    }
+  if (GPR_UNLIKELY(slice_count == sb->capacity)) {
+    do_embiggen(sb, slice_count, slice_offset);
   }
 }
 
@@ -375,6 +385,24 @@ grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer* sb) {
   return slice;
 }
 
+void grpc_slice_buffer_remove_first(grpc_slice_buffer* sb) {
+  GPR_DEBUG_ASSERT(sb->count > 0);
+  sb->length -= GRPC_SLICE_LENGTH(sb->slices[0]);
+  grpc_slice_unref_internal(sb->slices[0]);
+  sb->slices++;
+  if (--sb->count == 0) {
+    sb->slices = sb->base_slices;
+  }
+}
+
+void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin,
+                                 size_t end) {
+  // TODO(soheil): Introduce a ptr version for sub.
+  sb->length -= GRPC_SLICE_LENGTH(sb->slices[0]);
+  sb->slices[0] = grpc_slice_sub_no_ref(sb->slices[0], begin, end);
+  sb->length += end - begin;
+}
+
 void grpc_slice_buffer_undo_take_first(grpc_slice_buffer* sb,
                                        grpc_slice slice) {
   sb->slices--;
index 942830a..c20eca9 100644 (file)
@@ -138,7 +138,7 @@ SliceHashTable<T>::~SliceHashTable() {
 
 template <typename T>
 void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
-  const size_t hash = grpc_slice_hash(key);
+  const size_t hash = grpc_slice_hash_internal(key);
   for (size_t offset = 0; offset < size_; ++offset) {
     const size_t idx = (hash + offset) % size_;
     if (!entries_[idx].is_set) {
@@ -156,7 +156,7 @@ void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
 
 template <typename T>
 const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
-  const size_t hash = grpc_slice_hash(key);
+  const size_t hash = grpc_slice_hash_internal(key);
   // We cap the number of probes at the max number recorded when
   // populating the table.
   for (size_t offset = 0; offset <= max_num_probes_; ++offset) {
index 0f190c1..81d34dd 100644 (file)
@@ -19,6 +19,7 @@
 #include <grpc/support/port_platform.h>
 
 #include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_utils.h"
 
 #include <inttypes.h>
 #include <string.h>
@@ -127,10 +128,7 @@ int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
   return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
 }
 
-uint32_t grpc_slice_hash(grpc_slice s) {
-  return s.refcount == nullptr ? grpc_slice_default_hash_impl(s)
-                               : s.refcount->Hash(s);
-}
+uint32_t grpc_slice_hash(grpc_slice s) { return grpc_slice_hash_internal(s); }
 
 grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
                                           bool* returned_slice_is_different) {
@@ -138,12 +136,13 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
     return slice;
   }
 
-  uint32_t hash = grpc_slice_hash(slice);
+  uint32_t hash = grpc_slice_hash_internal(slice);
   for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
     static_metadata_hash_ent ent =
         static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
     if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
-        grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) {
+        grpc_slice_eq_static_interned(slice,
+                                      grpc_static_slice_table[ent.idx])) {
       *returned_slice_is_different = true;
       return grpc_static_slice_table[ent.idx];
     }
@@ -152,25 +151,20 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
   return slice;
 }
 
-bool grpc_slice_is_interned(const grpc_slice& slice) {
-  return (slice.refcount &&
-          (slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
-           GRPC_IS_STATIC_METADATA_STRING(slice)));
-}
-
 grpc_slice grpc_slice_intern(grpc_slice slice) {
   GPR_TIMER_SCOPE("grpc_slice_intern", 0);
   if (GRPC_IS_STATIC_METADATA_STRING(slice)) {
     return slice;
   }
 
-  uint32_t hash = grpc_slice_hash(slice);
+  uint32_t hash = grpc_slice_hash_internal(slice);
 
   for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
     static_metadata_hash_ent ent =
         static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
     if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
-        grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) {
+        grpc_slice_eq_static_interned(slice,
+                                      grpc_static_slice_table[ent.idx])) {
       return grpc_static_slice_table[ent.idx];
     }
   }
@@ -183,7 +177,8 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
   /* search for an existing string */
   size_t idx = TABLE_IDX(hash, shard->capacity);
   for (s = shard->strs[idx]; s; s = s->bucket_next) {
-    if (s->hash == hash && grpc_slice_eq(slice, materialize(s))) {
+    if (s->hash == hash &&
+        grpc_slice_eq_static_interned(slice, materialize(s))) {
       if (s->refcnt.RefIfNonZero()) {
         gpr_mu_unlock(&shard->mu);
         return materialize(s);
@@ -234,7 +229,7 @@ void grpc_slice_intern_init(void) {
   max_static_metadata_hash_probe = 0;
   for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
     grpc_static_metadata_hash_values[i] =
-        grpc_slice_default_hash_impl(grpc_static_slice_table[i]);
+        grpc_slice_default_hash_internal(grpc_static_slice_table[i]);
     for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) {
       size_t slot = (grpc_static_metadata_hash_values[i] + j) %
                     GPR_ARRAY_SIZE(static_metadata_hash);
@@ -248,6 +243,10 @@ void grpc_slice_intern_init(void) {
       }
     }
   }
+  // Handle KV hash for all static mdelems.
+  for (size_t i = 0; i < GRPC_STATIC_MDELEM_COUNT; ++i) {
+    grpc_static_mdelem_table[i].HashInit();
+  }
 }
 
 void grpc_slice_intern_shutdown(void) {
index a9f6087..c6943fe 100644 (file)
 
 #include <grpc/support/port_platform.h>
 
+#include <grpc/support/log.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include <string.h>
 
 #include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -97,12 +100,15 @@ struct grpc_slice_refcount {
   enum class Type {
     STATIC,    // Refcount for a static metadata slice.
     INTERNED,  // Refcount for an interned slice.
+    NOP,       // No-Op
     REGULAR    // Refcount for non-static-metadata, non-interned slices.
   };
   typedef void (*DestroyerFn)(void*);
 
   grpc_slice_refcount() = default;
 
+  explicit grpc_slice_refcount(Type t) : ref_type_(t) {}
+
   explicit grpc_slice_refcount(grpc_slice_refcount* sub) : sub_refcount_(sub) {}
   // Regular constructor for grpc_slice_refcount.
   //
@@ -198,6 +204,7 @@ inline int grpc_slice_refcount::Eq(const grpc_slice& a, const grpc_slice& b) {
       return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
     case Type::INTERNED:
       return a.refcount == b.refcount;
+    case Type::NOP:
     case Type::REGULAR:
       break;
   }
@@ -215,6 +222,7 @@ inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
     case Type::INTERNED:
       return reinterpret_cast<grpc_core::InternedSliceRefcount*>(slice.refcount)
           ->hash;
+    case Type::NOP:
     case Type::REGULAR:
       break;
   }
@@ -240,8 +248,33 @@ void grpc_slice_buffer_partial_unref_internal(grpc_slice_buffer* sb,
                                               size_t idx);
 void grpc_slice_buffer_destroy_internal(grpc_slice_buffer* sb);
 
+// Returns a pointer to the first slice in the slice buffer without giving
+// ownership to or a reference count on that slice.
+inline grpc_slice* grpc_slice_buffer_peek_first(grpc_slice_buffer* sb) {
+  GPR_DEBUG_ASSERT(sb->count > 0);
+  return &sb->slices[0];
+}
+
+// Removes the first slice from the slice buffer.
+void grpc_slice_buffer_remove_first(grpc_slice_buffer* sb);
+
+// Calls grpc_slice_sub with the given parameters on the first slice.
+void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin,
+                                 size_t end);
+
 /* Check if a slice is interned */
 bool grpc_slice_is_interned(const grpc_slice& slice);
+inline bool grpc_slice_is_interned(const grpc_slice& slice) {
+  return (slice.refcount &&
+          (slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
+           slice.refcount->GetType() == grpc_slice_refcount::Type::STATIC));
+}
+
+inline bool grpc_slice_static_interned_equal(const grpc_slice& a,
+                                             const grpc_slice& b) {
+  GPR_DEBUG_ASSERT(grpc_slice_is_interned(a) && grpc_slice_is_interned(b));
+  return a.refcount == b.refcount;
+}
 
 void grpc_slice_intern_init(void);
 void grpc_slice_intern_shutdown(void);
@@ -255,6 +288,25 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
 uint32_t grpc_static_slice_hash(grpc_slice s);
 int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
 
+inline uint32_t grpc_slice_hash_refcounted(const grpc_slice& s) {
+  GPR_DEBUG_ASSERT(s.refcount != nullptr);
+  return s.refcount->Hash(s);
+}
+
+inline uint32_t grpc_slice_default_hash_internal(const grpc_slice& s) {
+  return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
+                          g_hash_seed);
+}
+
+inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
+  return s.refcount == nullptr ? grpc_slice_default_hash_internal(s)
+                               : grpc_slice_hash_refcounted(s);
+}
+
+grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
+                                        size_t len);
+grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p);
+
 // Returns the memory used by this slice, not counting the slice structure
 // itself. This means that inlined and slices from static strings will return
 // 0. All other slices will return the size of the allocated chars.
index 6af9c33..7887e03 100644 (file)
 #include <grpc/support/log.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-char* grpc_dump_slice(grpc_slice s, uint32_t flags) {
+char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) {
   return gpr_dump(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
                   GRPC_SLICE_LENGTH(s), flags);
 }
 
+grpc_slice grpc_dump_slice_to_slice(const grpc_slice& s, uint32_t flags) {
+  size_t len;
+  grpc_core::UniquePtr<char> ptr(
+      gpr_dump_return_len(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
+                          GRPC_SLICE_LENGTH(s), flags, &len));
+  return grpc_slice_from_moved_buffer(std::move(ptr), len);
+}
+
 /** Finds the initial (\a begin) and final (\a end) offsets of the next
  * substring from \a str + \a read_offset until the next \a sep or the end of \a
  * str.
index 976f724..6551a6d 100644 (file)
@@ -30,7 +30,9 @@
 #include "src/core/lib/gpr/string.h"
 
 /* Calls gpr_dump on a slice. */
-char* grpc_dump_slice(grpc_slice slice, uint32_t flags);
+char* grpc_dump_slice(const grpc_slice& slice, uint32_t flags);
+/* Calls gpr_dump on a slice and returns the result as a slice. */
+grpc_slice grpc_dump_slice_to_slice(const grpc_slice& slice, uint32_t flags);
 
 /** Split \a str by the separator \a sep. Results are stored in \a dst, which
  * should be a properly initialized instance. */
diff --git a/src/core/lib/slice/slice_utils.h b/src/core/lib/slice/slice_utils.h
new file mode 100644 (file)
index 0000000..7589bf8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2019 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_SLICE_SLICE_UTILS_H
+#define GRPC_CORE_LIB_SLICE_SLICE_UTILS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
+
+// When we compare two slices, and we know the latter is not inlined, we can
+// short circuit our comparison operator. We specifically use differs()
+// semantics instead of equals() semantics due to more favourable code
+// generation when using differs(). Specifically, we may use the output of
+// grpc_slice_differs_refcounted for control flow. If we use differs()
+// semantics, we end with a tailcall to memcmp(). If we use equals() semantics,
+// we need to invert the result that memcmp provides us, which costs several
+// instructions to do so. If we're using the result for control flow (i.e.
+// branching based on the output) then we're just performing the extra
+// operations to invert the result pointlessly. Concretely, we save 6 ops on
+// x86-64/clang with differs().
+int grpc_slice_differs_refcounted(const grpc_slice& a,
+                                  const grpc_slice& b_not_inline);
+// When we compare two slices, and we *know* that one of them is static or
+// interned, we can short circuit our slice equality function. The second slice
+// here must be static or interned; slice a can be any slice, inlined or not.
+inline bool grpc_slice_eq_static_interned(const grpc_slice& a,
+                                          const grpc_slice& b_static_interned) {
+  if (a.refcount == b_static_interned.refcount) {
+    return true;
+  }
+  return !grpc_slice_differs_refcounted(a, b_static_interned);
+}
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_UTILS_H */
index 1335c81..8c5562b 100644 (file)
@@ -47,7 +47,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
   /// Add a mapping from \a key to \a value, taking ownership of \a key. This
   /// operation will always succeed. It may discard older entries.
   void Add(const grpc_slice& key, T value) {
-    const size_t idx = grpc_slice_hash(key) % Size;
+    const size_t idx = grpc_slice_hash_internal(key) % Size;
     entries_[idx].Set(key, std::move(value));
     return;
   }
@@ -55,7 +55,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
   /// Returns the value from the table associated with / \a key or null if not
   /// found.
   const T* Get(const grpc_slice& key) const {
-    const size_t idx = grpc_slice_hash(key) % Size;
+    const size_t idx = grpc_slice_hash_internal(key) % Size;
     const auto& entry = entries_[idx];
     return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
   }
index 275111f..2ccd335 100644 (file)
@@ -42,8 +42,8 @@
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/slice/slice_utils.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/call_test_only.h"
@@ -74,7 +74,7 @@
 #define ESTIMATED_MDELEM_COUNT 16
 
 struct batch_control {
-  batch_control() { gpr_ref_init(&steps_to_complete, 0); }
+  batch_control() = default;
 
   grpc_call* call = nullptr;
   grpc_transport_stream_op_batch op;
@@ -99,8 +99,14 @@ struct batch_control {
   } completion_data;
   grpc_closure start_batch;
   grpc_closure finish_batch;
-  gpr_refcount steps_to_complete;
+  grpc_core::Atomic<intptr_t> steps_to_complete;
   gpr_atm batch_error = reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE);
+  void set_num_steps_to_complete(uintptr_t steps) {
+    steps_to_complete.Store(steps, grpc_core::MemoryOrder::RELEASE);
+  }
+  bool completed_batch_step() {
+    return steps_to_complete.FetchSub(1, grpc_core::MemoryOrder::ACQ_REL) == 1;
+  }
 };
 
 struct parent_call {
@@ -349,8 +355,8 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
                MAX_SEND_EXTRA_METADATA_COUNT);
     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)) {
+      if (grpc_slice_eq_static_interned(
+              GRPC_MDKEY(args->add_initial_metadata[i]), GRPC_MDSTR_PATH)) {
         path = grpc_slice_ref_internal(
             GRPC_MDVALUE(args->add_initial_metadata[i]));
       }
@@ -899,7 +905,7 @@ static int prepare_application_metadata(grpc_call* call, int count,
     if (!GRPC_LOG_IF_ERROR("validate_metadata",
                            grpc_validate_header_key_is_legal(md->key))) {
       break;
-    } else if (!grpc_is_binary_header(md->key) &&
+    } else if (!grpc_is_binary_header_internal(md->key) &&
                !GRPC_LOG_IF_ERROR(
                    "validate_metadata",
                    grpc_validate_header_nonbin_value_is_legal(md->value))) {
@@ -1225,7 +1231,7 @@ static void post_batch_completion(batch_control* bctl) {
 }
 
 static void finish_batch_step(batch_control* bctl) {
-  if (GPR_UNLIKELY(gpr_unref(&bctl->steps_to_complete))) {
+  if (GPR_UNLIKELY(bctl->completed_batch_step())) {
     post_batch_completion(bctl);
   }
 }
@@ -1866,7 +1872,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
   if (!is_notify_tag_closure) {
     GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag));
   }
-  gpr_ref_init(&bctl->steps_to_complete, (has_send_ops ? 1 : 0) + num_recv_ops);
+  bctl->set_num_steps_to_complete((has_send_ops ? 1 : 0) + num_recv_ops);
 
   if (has_send_ops) {
     GRPC_CLOSURE_INIT(&bctl->finish_batch, finish_batch, bctl,
index e47cb43..e615507 100644 (file)
@@ -33,6 +33,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/channel/channelz.h"
+#include "src/core/lib/channel/channelz_registry.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
@@ -59,23 +60,6 @@ typedef struct registered_call {
   struct registered_call* next;
 } registered_call;
 
-struct grpc_channel {
-  int is_client;
-  grpc_compression_options compression_options;
-
-  gpr_atm call_size_estimate;
-  grpc_resource_user* resource_user;
-
-  gpr_mu registered_call_mu;
-  registered_call* registered_calls;
-
-  grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
-
-  char* target;
-};
-
-#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
-
 static void destroy_channel(void* arg, grpc_error* error);
 
 grpc_channel* grpc_channel_create_with_builder(
@@ -103,18 +87,9 @@ grpc_channel* grpc_channel_create_with_builder(
     grpc_channel_args_destroy(args);
     return channel;
   }
-
   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 =
-      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.
-  grpc_core::channelz::ChannelNodeCreationFunc channel_node_create_func =
-      grpc_core::channelz::ChannelNode::MakeChannelNode;
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = nullptr;
 
@@ -146,40 +121,16 @@ grpc_channel* grpc_channel_create_with_builder(
       channel->compression_options.enabled_algorithms_bitset =
           static_cast<uint32_t>(args->args[i].value.integer) |
           0x1; /* always support no compression */
-    } else if (0 == strcmp(args->args[i].key,
-                           GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) {
-      const grpc_integer_options options = {
-          GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX};
-      channel_tracer_max_memory =
-          (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
-    } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
-      // channelz will not be enabled by default until all concerns in
-      // https://github.com/grpc/grpc/issues/15986 are addressed.
-      channelz_enabled = grpc_channel_arg_get_bool(
-          &args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT);
-    } else if (0 == strcmp(args->args[i].key,
-                           GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC)) {
+    } else if (0 == strcmp(args->args[i].key, GRPC_ARG_CHANNELZ_CHANNEL_NODE)) {
       GPR_ASSERT(args->args[i].type == GRPC_ARG_POINTER);
       GPR_ASSERT(args->args[i].value.pointer.p != nullptr);
-      channel_node_create_func =
-          reinterpret_cast<grpc_core::channelz::ChannelNodeCreationFunc>(
-              args->args[i].value.pointer.p);
-    } else if (0 == strcmp(args->args[i].key,
-                           GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL)) {
-      internal_channel = grpc_channel_arg_get_bool(&args->args[i], false);
+      channel->channelz_node = static_cast<grpc_core::channelz::ChannelNode*>(
+                                   args->args[i].value.pointer.p)
+                                   ->Ref();
     }
   }
 
   grpc_channel_args_destroy(args);
-  // we only need to do the channelz bookkeeping for clients here. The channelz
-  // bookkeeping for server channels occurs in src/core/lib/surface/server.cc
-  if (channelz_enabled && channel->is_client) {
-    channel->channelz_channel = channel_node_create_func(
-        channel, channel_tracer_max_memory, !internal_channel);
-    channel->channelz_channel->AddTraceEvent(
-        grpc_core::channelz::ChannelTrace::Severity::Info,
-        grpc_slice_from_static_string("Channel created"));
-  }
   return channel;
 }
 
@@ -214,11 +165,71 @@ static grpc_channel_args* build_channel_args(
   return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
 }
 
-grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
-    grpc_channel* channel) {
-  return channel->channelz_channel.get();
+namespace {
+
+void* channelz_node_copy(void* p) {
+  grpc_core::channelz::ChannelNode* node =
+      static_cast<grpc_core::channelz::ChannelNode*>(p);
+  node->Ref().release();
+  return p;
+}
+void channelz_node_destroy(void* p) {
+  grpc_core::channelz::ChannelNode* node =
+      static_cast<grpc_core::channelz::ChannelNode*>(p);
+  node->Unref();
+}
+int channelz_node_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
+const grpc_arg_pointer_vtable channelz_node_arg_vtable = {
+    channelz_node_copy, channelz_node_destroy, channelz_node_cmp};
+
+void CreateChannelzNode(grpc_channel_stack_builder* builder) {
+  const grpc_channel_args* args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  // Check whether channelz is enabled.
+  const bool channelz_enabled = grpc_channel_arg_get_bool(
+      grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ),
+      GRPC_ENABLE_CHANNELZ_DEFAULT);
+  if (!channelz_enabled) return;
+  // Get parameters needed to create the channelz node.
+  const size_t channel_tracer_max_memory = grpc_channel_arg_get_integer(
+      grpc_channel_args_find(args,
+                             GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+      {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX});
+  const intptr_t channelz_parent_uuid =
+      grpc_core::channelz::GetParentUuidFromArgs(*args);
+  // Create the channelz node.
+  grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_node =
+      grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
+          grpc_core::UniquePtr<char>(
+              gpr_strdup(grpc_channel_stack_builder_get_target(builder))),
+          channel_tracer_max_memory, channelz_parent_uuid);
+  channelz_node->AddTraceEvent(
+      grpc_core::channelz::ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("Channel created"));
+  // Update parent channel node, if any.
+  if (channelz_parent_uuid > 0) {
+    grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
+        grpc_core::channelz::ChannelzRegistry::Get(channelz_parent_uuid);
+    if (parent_node != nullptr) {
+      grpc_core::channelz::ChannelNode* parent =
+          static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
+      parent->AddChildChannel(channelz_node->uuid());
+    }
+  }
+  // Add channelz node to channel args.
+  // We remove the arg for the parent uuid, since we no longer need it.
+  grpc_arg new_arg = grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_NODE), channelz_node.get(),
+      &channelz_node_arg_vtable);
+  const char* args_to_remove[] = {GRPC_ARG_CHANNELZ_PARENT_UUID};
+  grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
+      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
+  grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
+  grpc_channel_args_destroy(new_args);
 }
 
+}  // namespace
+
 grpc_channel* grpc_channel_create(const char* target,
                                   const grpc_channel_args* input_args,
                                   grpc_channel_stack_type channel_stack_type,
@@ -241,9 +252,12 @@ grpc_channel* grpc_channel_create(const char* target,
     }
     return nullptr;
   }
-  grpc_channel* channel =
-      grpc_channel_create_with_builder(builder, channel_stack_type);
-  return channel;
+  // We only need to do this for clients here. For servers, this will be
+  // done in src/core/lib/surface/server.cc.
+  if (grpc_channel_stack_type_is_client(channel_stack_type)) {
+    CreateChannelzNode(builder);
+  }
+  return grpc_channel_create_with_builder(builder, channel_stack_type);
 }
 
 size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) {
@@ -421,29 +435,23 @@ grpc_call* grpc_channel_create_registered_call(
   return call;
 }
 
-#ifndef NDEBUG
-#define REF_REASON reason
-#define REF_ARG , const char* reason
-#else
-#define REF_REASON ""
-#define REF_ARG
-#endif
-void grpc_channel_internal_ref(grpc_channel* c REF_ARG) {
-  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
-}
-
-void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
-  GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
-}
-
 static void destroy_channel(void* arg, grpc_error* error) {
   grpc_channel* channel = static_cast<grpc_channel*>(arg);
-  if (channel->channelz_channel != nullptr) {
-    channel->channelz_channel->AddTraceEvent(
+  if (channel->channelz_node != nullptr) {
+    if (channel->channelz_node->parent_uuid() > 0) {
+      grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
+          grpc_core::channelz::ChannelzRegistry::Get(
+              channel->channelz_node->parent_uuid());
+      if (parent_node != nullptr) {
+        grpc_core::channelz::ChannelNode* parent =
+            static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
+        parent->RemoveChildChannel(channel->channelz_node->uuid());
+      }
+    }
+    channel->channelz_node->AddTraceEvent(
         grpc_core::channelz::ChannelTrace::Severity::Info,
         grpc_slice_from_static_string("Channel destroyed"));
-    channel->channelz_channel->MarkChannelDestroyed();
-    channel->channelz_channel.reset();
+    channel->channelz_node.reset();
   }
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   while (channel->registered_calls) {
@@ -475,25 +483,9 @@ void grpc_channel_destroy(grpc_channel* channel) {
   GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
 }
 
-grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel) {
-  return CHANNEL_STACK_FROM_CHANNEL(channel);
-}
-
-grpc_compression_options grpc_channel_compression_options(
-    const grpc_channel* channel) {
-  return channel->compression_options;
-}
-
-grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel, int i) {
+grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
+                                                         int i) {
   char tmp[GPR_LTOA_MIN_BUFSIZE];
-  switch (i) {
-    case 0:
-      return GRPC_MDELEM_GRPC_STATUS_0;
-    case 1:
-      return GRPC_MDELEM_GRPC_STATUS_1;
-    case 2:
-      return GRPC_MDELEM_GRPC_STATUS_2;
-  }
   gpr_ltoa(i, tmp);
   return grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_STATUS,
                                  grpc_slice_from_copied_string(tmp));
index ab00b8e..a4cac74 100644 (file)
@@ -59,22 +59,76 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
     status_code.
 
     The returned elem is owned by the caller. */
-grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
-                                                int status_code);
+grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
+                                                         int status_code);
+inline grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
+                                                       int status_code) {
+  switch (status_code) {
+    case 0:
+      return GRPC_MDELEM_GRPC_STATUS_0;
+    case 1:
+      return GRPC_MDELEM_GRPC_STATUS_1;
+    case 2:
+      return GRPC_MDELEM_GRPC_STATUS_2;
+  }
+  return grpc_channel_get_reffed_status_elem_slowpath(channel, status_code);
+}
 
 size_t grpc_channel_get_call_size_estimate(grpc_channel* channel);
 void grpc_channel_update_call_size_estimate(grpc_channel* channel, size_t size);
 
+struct registered_call;
+struct grpc_channel {
+  int is_client;
+  grpc_compression_options compression_options;
+
+  gpr_atm call_size_estimate;
+  grpc_resource_user* resource_user;
+
+  gpr_mu registered_call_mu;
+  registered_call* registered_calls;
+
+  grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_node;
+
+  char* target;
+};
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
+
+inline grpc_compression_options grpc_channel_compression_options(
+    const grpc_channel* channel) {
+  return channel->compression_options;
+}
+
+inline grpc_channel_stack* grpc_channel_get_channel_stack(
+    grpc_channel* channel) {
+  return CHANNEL_STACK_FROM_CHANNEL(channel);
+}
+
+inline grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
+    grpc_channel* channel) {
+  return channel->channelz_node.get();
+}
+
 #ifndef NDEBUG
-void grpc_channel_internal_ref(grpc_channel* channel, const char* reason);
-void grpc_channel_internal_unref(grpc_channel* channel, const char* reason);
+inline void grpc_channel_internal_ref(grpc_channel* channel,
+                                      const char* reason) {
+  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
+}
+inline void grpc_channel_internal_unref(grpc_channel* channel,
+                                        const char* reason) {
+  GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
+}
 #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
   grpc_channel_internal_ref(channel, reason)
 #define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
   grpc_channel_internal_unref(channel, reason)
 #else
-void grpc_channel_internal_ref(grpc_channel* channel);
-void grpc_channel_internal_unref(grpc_channel* channel);
+inline void grpc_channel_internal_ref(grpc_channel* channel) {
+  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
+}
+inline void grpc_channel_internal_unref(grpc_channel* channel) {
+  GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
+}
 #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
   grpc_channel_internal_ref(channel)
 #define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
index e796071..60a7d78 100644 (file)
@@ -34,6 +34,7 @@
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/gprpp/atomic.h"
+#include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
@@ -200,7 +201,7 @@ struct cq_vtable {
   bool (*begin_op)(grpc_completion_queue* cq, void* tag);
   void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
                  void (*done)(void* done_arg, grpc_cq_completion* storage),
-                 void* done_arg, grpc_cq_completion* storage);
+                 void* done_arg, grpc_cq_completion* storage, bool internal);
   grpc_event (*next)(grpc_completion_queue* cq, gpr_timespec deadline,
                      void* reserved);
   grpc_event (*pluck)(grpc_completion_queue* cq, void* tag,
@@ -354,23 +355,20 @@ static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag);
 // queue. The done argument is a callback that will be invoked when it is
 // safe to free up that storage. The storage MUST NOT be freed until the
 // done callback is invoked.
-static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
-                               grpc_error* error,
-                               void (*done)(void* done_arg,
-                                            grpc_cq_completion* storage),
-                               void* done_arg, grpc_cq_completion* storage);
-
-static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
-                                grpc_error* error,
-                                void (*done)(void* done_arg,
-                                             grpc_cq_completion* storage),
-                                void* done_arg, grpc_cq_completion* storage);
-
-static void cq_end_op_for_callback(grpc_completion_queue* cq, void* tag,
-                                   grpc_error* error,
-                                   void (*done)(void* done_arg,
-                                                grpc_cq_completion* storage),
-                                   void* done_arg, grpc_cq_completion* storage);
+static void cq_end_op_for_next(
+    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
+    grpc_cq_completion* storage, bool internal);
+
+static void cq_end_op_for_pluck(
+    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
+    grpc_cq_completion* storage, bool internal);
+
+static void cq_end_op_for_callback(
+    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
+    grpc_cq_completion* storage, bool internal);
 
 static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
                           void* reserved);
@@ -674,11 +672,10 @@ bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag) {
 /* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
  * completion
  * type of GRPC_CQ_NEXT) */
-static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
-                               grpc_error* error,
-                               void (*done)(void* done_arg,
-                                            grpc_cq_completion* storage),
-                               void* done_arg, grpc_cq_completion* storage) {
+static void cq_end_op_for_next(
+    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
+    grpc_cq_completion* storage, bool internal) {
   GPR_TIMER_SCOPE("cq_end_op_for_next", 0);
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
@@ -754,11 +751,10 @@ static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
 /* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
  * completion
  * type of GRPC_CQ_PLUCK) */
-static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
-                                grpc_error* error,
-                                void (*done)(void* done_arg,
-                                             grpc_cq_completion* storage),
-                                void* done_arg, grpc_cq_completion* storage) {
+static void cq_end_op_for_pluck(
+    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
+    grpc_cq_completion* storage, bool internal) {
   GPR_TIMER_SCOPE("cq_end_op_for_pluck", 0);
 
   cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
@@ -821,15 +817,19 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
   GRPC_ERROR_UNREF(error);
 }
 
+static void functor_callback(void* arg, grpc_error* error) {
+  auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(arg);
+  functor->functor_run(functor, error == GRPC_ERROR_NONE);
+}
+
 /* Complete an event on a completion queue of type GRPC_CQ_CALLBACK */
 static void cq_end_op_for_callback(
     grpc_completion_queue* cq, void* tag, grpc_error* error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
-    grpc_cq_completion* storage) {
+    grpc_cq_completion* storage, bool internal) {
   GPR_TIMER_SCOPE("cq_end_op_for_callback", 0);
 
   cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
-  bool is_success = (error == GRPC_ERROR_NONE);
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
@@ -856,16 +856,25 @@ static void cq_end_op_for_callback(
     cq_finish_shutdown_callback(cq);
   }
 
-  GRPC_ERROR_UNREF(error);
-
   auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
-  grpc_core::ApplicationCallbackExecCtx::Enqueue(functor, is_success);
+  if (internal) {
+    grpc_core::ApplicationCallbackExecCtx::Enqueue(functor,
+                                                   (error == GRPC_ERROR_NONE));
+    GRPC_ERROR_UNREF(error);
+  } else {
+    GRPC_CLOSURE_SCHED(
+        GRPC_CLOSURE_CREATE(
+            functor_callback, functor,
+            grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
+        error);
+  }
 }
 
 void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
-                    void* done_arg, grpc_cq_completion* storage) {
-  cq->vtable->end_op(cq, tag, error, done, done_arg, storage);
+                    void* done_arg, grpc_cq_completion* storage,
+                    bool internal) {
+  cq->vtable->end_op(cq, tag, error, done, done_arg, storage, internal);
 }
 
 typedef struct {
@@ -1343,7 +1352,11 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
   GPR_ASSERT(cqd->shutdown_called);
 
   cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
-  grpc_core::ApplicationCallbackExecCtx::Enqueue(callback, true);
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_CREATE(
+          functor_callback, callback,
+          grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
+      GRPC_ERROR_NONE);
 }
 
 static void cq_shutdown_callback(grpc_completion_queue* cq) {
index d60fe6d..3ba9fbb 100644 (file)
@@ -77,7 +77,8 @@ bool grpc_cq_begin_op(grpc_completion_queue* cc, void* tag);
    grpc_cq_begin_op */
 void grpc_cq_end_op(grpc_completion_queue* cc, void* tag, grpc_error* error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
-                    void* done_arg, grpc_cq_completion* storage);
+                    void* done_arg, grpc_cq_completion* storage,
+                    bool internal = false);
 
 grpc_pollset* grpc_cq_pollset(grpc_completion_queue* cc);
 
index 2377c4d..8f6df48 100644 (file)
@@ -513,7 +513,7 @@ static void publish_call(grpc_server* server, call_data* calld, size_t cq_idx,
   }
 
   grpc_cq_end_op(calld->cq_new, rc->tag, GRPC_ERROR_NONE, done_request_event,
-                 rc, &rc->completion);
+                 rc, &rc->completion, true);
 }
 
 static void publish_new_rpc(void* arg, grpc_error* error) {
@@ -625,8 +625,8 @@ static void start_new_rpc(grpc_call_element* elem) {
   if (chand->registered_methods && calld->path_set && calld->host_set) {
     /* TODO(ctiller): unify these two searches */
     /* check for an exact match with host */
-    hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host),
-                              grpc_slice_hash(calld->path));
+    hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_internal(calld->host),
+                              grpc_slice_hash_internal(calld->path));
     for (i = 0; i <= chand->registered_method_max_probes; i++) {
       rm = &chand->registered_methods[(hash + i) %
                                       chand->registered_method_slots];
@@ -644,7 +644,7 @@ static void start_new_rpc(grpc_call_element* elem) {
       return;
     }
     /* check for a wildcard method definition (no host set) */
-    hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path));
+    hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash_internal(calld->path));
     for (i = 0; i <= chand->registered_method_max_probes; i++) {
       rm = &chand->registered_methods[(hash + i) %
                                       chand->registered_method_slots];
@@ -1194,14 +1194,14 @@ void grpc_server_setup_transport(
       bool has_host;
       grpc_slice method;
       if (rm->host != nullptr) {
-        host = grpc_slice_intern(grpc_slice_from_static_string(rm->host));
+        host = grpc_slice_from_static_string(rm->host);
         has_host = true;
       } else {
         has_host = false;
       }
-      method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
-      hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0,
-                                grpc_slice_hash(method));
+      method = grpc_slice_from_static_string(rm->method);
+      hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash_internal(host) : 0,
+                                grpc_slice_hash_internal(method));
       for (probes = 0; chand->registered_methods[(hash + probes) % slots]
                            .server_registered_method != nullptr;
            probes++)
index 2dd18f3..0f65091 100644 (file)
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/validate_metadata.h"
 
-static grpc_error* conforms_to(grpc_slice slice, const uint8_t* legal_bits,
+static grpc_error* conforms_to(const grpc_slice& slice,
+                               const uint8_t* legal_bits,
                                const char* err_desc) {
   const uint8_t* p = GRPC_SLICE_START_PTR(slice);
   const uint8_t* e = GRPC_SLICE_END_PTR(slice);
@@ -38,13 +40,12 @@ static grpc_error* conforms_to(grpc_slice slice, const uint8_t* legal_bits,
     int byte = idx / 8;
     int bit = idx % 8;
     if ((legal_bits[byte] & (1 << bit)) == 0) {
-      char* dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
       grpc_error* error = grpc_error_set_str(
           grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc),
                              GRPC_ERROR_INT_OFFSET,
                              p - GRPC_SLICE_START_PTR(slice)),
-          GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(dump));
-      gpr_free(dump);
+          GRPC_ERROR_STR_RAW_BYTES,
+          grpc_dump_slice_to_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
       return error;
     }
   }
@@ -57,7 +58,7 @@ static int error2int(grpc_error* error) {
   return r;
 }
 
-grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice) {
+grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice) {
   static const uint8_t legal_header_bits[256 / 8] = {
       0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
       0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -77,7 +78,8 @@ int grpc_header_key_is_legal(grpc_slice slice) {
   return error2int(grpc_validate_header_key_is_legal(slice));
 }
 
-grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) {
+grpc_error* grpc_validate_header_nonbin_value_is_legal(
+    const grpc_slice& slice) {
   static const uint8_t legal_header_bits[256 / 8] = {
       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
       0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -89,7 +91,11 @@ int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
   return error2int(grpc_validate_header_nonbin_value_is_legal(slice));
 }
 
+int grpc_is_binary_header_internal(const grpc_slice& slice) {
+  return grpc_key_is_binary_header(GRPC_SLICE_START_PTR(slice),
+                                   GRPC_SLICE_LENGTH(slice));
+}
+
 int grpc_is_binary_header(grpc_slice slice) {
-  if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
-  return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
+  return grpc_is_binary_header_internal(slice);
 }
index e87fb7b..db3be68 100644 (file)
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/error.h"
 
-grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice);
-grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
+grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice);
+grpc_error* grpc_validate_header_nonbin_value_is_legal(const grpc_slice& slice);
+
+int grpc_is_binary_header_internal(const grpc_slice& slice);
+inline int grpc_key_is_binary_header(const uint8_t* buf, size_t length) {
+  if (length < 5) return 0;
+  return 0 == memcmp(buf + length - 4, "-bin", 4);
+}
+inline int grpc_is_refcounted_slice_binary_header(const grpc_slice& slice) {
+  GPR_DEBUG_ASSERT(slice.refcount != nullptr);
+  return grpc_key_is_binary_header(slice.data.refcounted.bytes,
+                                   slice.data.refcounted.length);
+}
 
 #endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */
index 8aeadaf..7d9d49b 100644 (file)
@@ -25,4 +25,4 @@
 
 const char* grpc_version_string(void) { return "7.0.0"; }
 
-const char* grpc_g_stands_for(void) { return "gandalf"; }
+const char* grpc_g_stands_for(void) { return "gale"; }
index 4609eb4..1523ced 100644 (file)
@@ -43,6 +43,7 @@
 
 using grpc_core::AllocatedMetadata;
 using grpc_core::InternedMetadata;
+using grpc_core::StaticMetadata;
 using grpc_core::UserData;
 
 /* There are two kinds of mdelem and mdstr instances.
@@ -100,15 +101,20 @@ void grpc_mdelem_trace_unref(void* md, const grpc_slice& key,
 #define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity))
 #define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1))
 
+void StaticMetadata::HashInit() {
+  uint32_t k_hash = grpc_slice_hash_internal(kv_.key);
+  uint32_t v_hash = grpc_slice_hash_internal(kv_.value);
+  hash_ = GRPC_MDSTR_KV_HASH(k_hash, v_hash);
+}
+
 AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
                                      const grpc_slice& value)
-    : key_(grpc_slice_ref_internal(key)),
-      value_(grpc_slice_ref_internal(value)),
-      refcnt_(1) {
+    : RefcountedMdBase(grpc_slice_ref_internal(key),
+                       grpc_slice_ref_internal(value)) {
 #ifndef NDEBUG
   if (grpc_trace_metadata.enabled()) {
-    char* key_str = grpc_slice_to_c_string(key_);
-    char* value_str = grpc_slice_to_c_string(value_);
+    char* key_str = grpc_slice_to_c_string(key);
+    char* value_str = grpc_slice_to_c_string(value);
     gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", this,
             RefValue(), key_str, value_str);
     gpr_free(key_str);
@@ -118,8 +124,8 @@ AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
 }
 
 AllocatedMetadata::~AllocatedMetadata() {
-  grpc_slice_unref_internal(key_);
-  grpc_slice_unref_internal(value_);
+  grpc_slice_unref_internal(key());
+  grpc_slice_unref_internal(value());
   void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
   if (user_data) {
     destroy_user_data_func destroy_user_data =
@@ -131,15 +137,13 @@ AllocatedMetadata::~AllocatedMetadata() {
 InternedMetadata::InternedMetadata(const grpc_slice& key,
                                    const grpc_slice& value, uint32_t hash,
                                    InternedMetadata* next)
-    : key_(grpc_slice_ref_internal(key)),
-      value_(grpc_slice_ref_internal(value)),
-      refcnt_(1),
-      hash_(hash),
+    : RefcountedMdBase(grpc_slice_ref_internal(key),
+                       grpc_slice_ref_internal(value), hash),
       link_(next) {
 #ifndef NDEBUG
   if (grpc_trace_metadata.enabled()) {
-    char* key_str = grpc_slice_to_c_string(key_);
-    char* value_str = grpc_slice_to_c_string(value_);
+    char* key_str = grpc_slice_to_c_string(key);
+    char* value_str = grpc_slice_to_c_string(value);
     gpr_log(GPR_DEBUG, "ELM   NEW:%p:%" PRIdPTR ": '%s' = '%s'", this,
             RefValue(), key_str, value_str);
     gpr_free(key_str);
@@ -149,8 +153,8 @@ InternedMetadata::InternedMetadata(const grpc_slice& key,
 }
 
 InternedMetadata::~InternedMetadata() {
-  grpc_slice_unref_internal(key_);
-  grpc_slice_unref_internal(value_);
+  grpc_slice_unref_internal(key());
+  grpc_slice_unref_internal(value());
   void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
   if (user_data) {
     destroy_user_data_func destroy_user_data =
@@ -223,17 +227,20 @@ void grpc_mdctx_global_shutdown() {
   }
 }
 
+#ifndef NDEBUG
 static int is_mdelem_static(grpc_mdelem e) {
-  return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] &&
-         GRPC_MDELEM_DATA(e) <
+  return reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) >=
+             &grpc_static_mdelem_table[0] &&
+         reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) <
              &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 }
+#endif
 
 void InternedMetadata::RefWithShardLocked(mdtab_shard* shard) {
 #ifndef NDEBUG
   if (grpc_trace_metadata.enabled()) {
-    char* key_str = grpc_slice_to_c_string(key_);
-    char* value_str = grpc_slice_to_c_string(value_);
+    char* key_str = grpc_slice_to_c_string(key());
+    char* value_str = grpc_slice_to_c_string(value());
     intptr_t value = RefValue();
     gpr_log(__FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG,
             "ELM   REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", this, value,
@@ -323,8 +330,8 @@ grpc_mdelem grpc_mdelem_create(
     }
   }
 
-  uint32_t hash =
-      GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value));
+  uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_refcounted(key),
+                                     grpc_slice_hash_refcounted(value));
   InternedMetadata* md;
   mdtab_shard* shard = &g_shards[SHARD_IDX(hash)];
   size_t idx;
@@ -391,8 +398,11 @@ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void*)) {
     case GRPC_MDELEM_STORAGE_EXTERNAL:
       return nullptr;
     case GRPC_MDELEM_STORAGE_STATIC:
-      return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
-                                                 grpc_static_mdelem_table];
+      return reinterpret_cast<void*>(
+          grpc_static_mdelem_user_data
+              [reinterpret_cast<grpc_core::StaticMetadata*>(
+                   GRPC_MDELEM_DATA(md)) -
+               grpc_static_mdelem_table]);
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
       auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
       return get_user_data(am->user_data(), destroy_func);
@@ -430,15 +440,18 @@ void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*),
       return nullptr;
     case GRPC_MDELEM_STORAGE_STATIC:
       destroy_func(data);
-      return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
-                                                 grpc_static_mdelem_table];
+      return reinterpret_cast<void*>(
+          grpc_static_mdelem_user_data
+              [reinterpret_cast<grpc_core::StaticMetadata*>(
+                   GRPC_MDELEM_DATA(md)) -
+               grpc_static_mdelem_table]);
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
       auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
       return set_user_data(am->user_data(), destroy_func, data);
     }
     case GRPC_MDELEM_STORAGE_INTERNED: {
       auto* im = reinterpret_cast<InternedMetadata*> GRPC_MDELEM_DATA(md);
-      GPR_ASSERT(!is_mdelem_static(md));
+      GPR_DEBUG_ASSERT(!is_mdelem_static(md));
       return set_user_data(im->user_data(), destroy_func, data);
     }
   }
@@ -482,3 +495,20 @@ void grpc_mdelem_do_unref(grpc_mdelem gmd DEBUG_ARGS) {
     }
   }
 }
+
+void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
+                                uint32_t hash DEBUG_ARGS) {
+  switch (storage) {
+    case GRPC_MDELEM_STORAGE_EXTERNAL:
+    case GRPC_MDELEM_STORAGE_STATIC:
+      return;
+    case GRPC_MDELEM_STORAGE_INTERNED: {
+      note_disposed_interned_metadata(hash);
+      break;
+    }
+    case GRPC_MDELEM_STORAGE_ALLOCATED: {
+      grpc_core::Delete(reinterpret_cast<AllocatedMetadata*>(ptr));
+      break;
+    }
+  }
+}
index c0d1ab3..3cef031 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "include/grpc/impl/codegen/log.h"
+#include <grpc/impl/codegen/log.h>
 
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
@@ -30,6 +30,7 @@
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/slice/slice_utils.h"
 
 extern grpc_core::DebugOnlyTraceFlag grpc_trace_metadata;
 
@@ -79,17 +80,22 @@ typedef struct grpc_mdelem_data {
    this bit set in their integer value */
 #define GRPC_MDELEM_STORAGE_INTERNED_BIT 1
 
+/* External and static storage metadata has no refcount to ref/unref. Allocated
+ * and interned metadata do have a refcount. Metadata ref and unref methods use
+ * a switch statement on this enum to determine which behaviour to execute.
+ * Keeping the no-ref cases together and the ref-cases together leads to
+ * slightly better code generation (9 inlined instructions rather than 10). */
 typedef enum {
   /* memory pointed to by grpc_mdelem::payload is owned by an external system */
   GRPC_MDELEM_STORAGE_EXTERNAL = 0,
-  /* memory pointed to by grpc_mdelem::payload is interned by the metadata
-     system */
-  GRPC_MDELEM_STORAGE_INTERNED = GRPC_MDELEM_STORAGE_INTERNED_BIT,
+  /* memory is in the static metadata table */
+  GRPC_MDELEM_STORAGE_STATIC = GRPC_MDELEM_STORAGE_INTERNED_BIT,
   /* memory pointed to by grpc_mdelem::payload is allocated by the metadata
      system */
   GRPC_MDELEM_STORAGE_ALLOCATED = 2,
-  /* memory is in the static metadata table */
-  GRPC_MDELEM_STORAGE_STATIC = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
+  /* memory pointed to by grpc_mdelem::payload is interned by the metadata
+     system */
+  GRPC_MDELEM_STORAGE_INTERNED = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
 } grpc_mdelem_data_storage;
 
 struct grpc_mdelem {
@@ -138,7 +144,17 @@ bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
  * grpc_mdelem_eq and remove unnecessary checks. */
 inline bool grpc_mdelem_static_value_eq(grpc_mdelem a, grpc_mdelem b_static) {
   if (a.payload == b_static.payload) return true;
-  return grpc_slice_eq(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static));
+  return grpc_slice_eq_static_interned(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static));
+}
+#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
+
+inline bool grpc_mdelem_both_interned_eq(grpc_mdelem a_interned,
+                                         grpc_mdelem b_interned) {
+  GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(a_interned) ||
+                   GRPC_MDISNULL(a_interned));
+  GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(b_interned) ||
+                   GRPC_MDISNULL(b_interned));
+  return a_interned.payload == b_interned.payload;
 }
 
 /* Mutator and accessor for grpc_mdelem user data. The destructor function
@@ -168,17 +184,34 @@ struct UserData {
   grpc_core::Atomic<void*> data;
 };
 
-class InternedMetadata {
+class StaticMetadata {
  public:
-  struct BucketLink {
-    explicit BucketLink(InternedMetadata* md) : next(md) {}
+  StaticMetadata(const grpc_slice& key, const grpc_slice& value)
+      : kv_({key, value}), hash_(0) {}
 
-    InternedMetadata* next = nullptr;
-  };
+  const grpc_mdelem_data& data() const { return kv_; }
 
-  InternedMetadata(const grpc_slice& key, const grpc_slice& value,
-                   uint32_t hash, InternedMetadata* next);
-  ~InternedMetadata();
+  void HashInit();
+  uint32_t hash() { return hash_; }
+
+ private:
+  grpc_mdelem_data kv_;
+
+  /* private only data */
+  uint32_t hash_;
+};
+
+class RefcountedMdBase {
+ public:
+  RefcountedMdBase(const grpc_slice& key, const grpc_slice& value)
+      : key_(key), value_(value), refcnt_(1) {}
+  RefcountedMdBase(const grpc_slice& key, const grpc_slice& value,
+                   uint32_t hash)
+      : key_(key), value_(value), refcnt_(1), hash_(hash) {}
+
+  const grpc_slice& key() const { return key_; }
+  const grpc_slice& value() const { return value_; }
+  uint32_t hash() { return hash_; }
 
 #ifndef NDEBUG
   void Ref(const char* file, int line) {
@@ -190,92 +223,65 @@ class InternedMetadata {
     grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
     return Unref();
   }
-#else
-  // We define a naked Ref() in the else-clause to make sure we don't
-  // inadvertently skip the assert on debug builds.
+#endif
   void Ref() {
     /* we can assume the ref count is >= 1 as the application is calling
        this function - meaning that no adjustment to mdtab_free is necessary,
        simplifying the logic here to be just an atomic increment */
     refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
   }
-#endif  // ifndef NDEBUG
   bool Unref() {
     const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
     GPR_DEBUG_ASSERT(prior > 0);
     return prior == 1;
   }
 
-  void RefWithShardLocked(mdtab_shard* shard);
-  const grpc_slice& key() const { return key_; }
-  const grpc_slice& value() const { return value_; }
-  UserData* user_data() { return &user_data_; }
-  uint32_t hash() { return hash_; }
-  InternedMetadata* bucket_next() { return link_.next; }
-  void set_bucket_next(InternedMetadata* md) { link_.next = md; }
-
-  static size_t CleanupLinkedMetadata(BucketLink* head);
-
- private:
+ protected:
+  intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
   bool AllRefsDropped() { return refcnt_.Load(MemoryOrder::ACQUIRE) == 0; }
   bool FirstRef() { return refcnt_.FetchAdd(1, MemoryOrder::RELAXED) == 0; }
-  intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
 
+ private:
   /* must be byte compatible with grpc_mdelem_data */
   grpc_slice key_;
   grpc_slice value_;
-
-  /* private only data */
   grpc_core::Atomic<intptr_t> refcnt_;
-  uint32_t hash_;
+  uint32_t hash_ = 0;
+};
 
-  UserData user_data_;
+class InternedMetadata : public RefcountedMdBase {
+ public:
+  struct BucketLink {
+    explicit BucketLink(InternedMetadata* md) : next(md) {}
+
+    InternedMetadata* next = nullptr;
+  };
+
+  InternedMetadata(const grpc_slice& key, const grpc_slice& value,
+                   uint32_t hash, InternedMetadata* next);
+  ~InternedMetadata();
+
+  void RefWithShardLocked(mdtab_shard* shard);
+  UserData* user_data() { return &user_data_; }
+  InternedMetadata* bucket_next() { return link_.next; }
+  void set_bucket_next(InternedMetadata* md) { link_.next = md; }
 
+  static size_t CleanupLinkedMetadata(BucketLink* head);
+
+ private:
+  UserData user_data_;
   BucketLink link_;
 };
 
 /* Shadow structure for grpc_mdelem_data for allocated elements */
-class AllocatedMetadata {
+class AllocatedMetadata : public RefcountedMdBase {
  public:
   AllocatedMetadata(const grpc_slice& key, const grpc_slice& value);
   ~AllocatedMetadata();
 
-  const grpc_slice& key() const { return key_; }
-  const grpc_slice& value() const { return value_; }
   UserData* user_data() { return &user_data_; }
 
-#ifndef NDEBUG
-  void Ref(const char* file, int line) {
-    grpc_mdelem_trace_ref(this, key_, value_, RefValue(), file, line);
-    Ref();
-  }
-  bool Unref(const char* file, int line) {
-    grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
-    return Unref();
-  }
-#endif  // ifndef NDEBUG
-  void Ref() {
-    /* we can assume the ref count is >= 1 as the application is calling
-       this function - meaning that no adjustment to mdtab_free is necessary,
-       simplifying the logic here to be just an atomic increment */
-    refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
-  }
-  bool Unref() {
-    const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
-    GPR_DEBUG_ASSERT(prior > 0);
-    return prior == 1;
-  }
-
  private:
-  intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
-
-  /* must be byte compatible with grpc_mdelem_data */
-  grpc_slice key_;
-  grpc_slice value_;
-
-  /* private only data */
-  grpc_core::Atomic<intptr_t> refcnt_;
-
   UserData user_data_;
 };
 
@@ -320,30 +326,40 @@ inline grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd) {
 
 #ifndef NDEBUG
 #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__)
-void grpc_mdelem_do_unref(grpc_mdelem gmd, const char* file, int line);
+void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
+                                uint32_t hash, const char* file, int line);
 inline void grpc_mdelem_unref(grpc_mdelem gmd, const char* file, int line) {
 #else
 #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s))
-void grpc_mdelem_do_unref(grpc_mdelem gmd);
+void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
+                                uint32_t hash);
 inline void grpc_mdelem_unref(grpc_mdelem gmd) {
 #endif
-  switch (GRPC_MDELEM_STORAGE(gmd)) {
+  const grpc_mdelem_data_storage storage = GRPC_MDELEM_STORAGE(gmd);
+  switch (storage) {
     case GRPC_MDELEM_STORAGE_EXTERNAL:
     case GRPC_MDELEM_STORAGE_STATIC:
       return;
     case GRPC_MDELEM_STORAGE_INTERNED:
     case GRPC_MDELEM_STORAGE_ALLOCATED:
+      auto* md =
+          reinterpret_cast<grpc_core::RefcountedMdBase*> GRPC_MDELEM_DATA(gmd);
+      /* once the refcount hits zero, some other thread can come along and
+         free an interned md at any time: it's unsafe from this point on to
+         access it so we read the hash now. */
+      uint32_t hash = md->hash();
+      if (GPR_UNLIKELY(md->Unref())) {
 #ifndef NDEBUG
-      grpc_mdelem_do_unref(gmd, file, line);
+        grpc_mdelem_on_final_unref(storage, md, hash, file, line);
 #else
-      grpc_mdelem_do_unref(gmd);
+        grpc_mdelem_on_final_unref(storage, md, hash);
 #endif
+      }
       return;
   }
 }
 
 #define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL)
-#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
 
 /* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */
 #define GRPC_MDELEM_LENGTH(e)                                                  \
index fc5bb64..bbf1736 100644 (file)
@@ -384,190 +384,276 @@ static const uint8_t elem_idxs[] = {
     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) {
+grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {
   if (a == -1 || b == -1) return GRPC_MDNULL;
-  uint32_t k = (uint32_t)(a * 107 + b);
+  uint32_t k = static_cast<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
-             ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]],
+             ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]].data(),
                                 GRPC_MDELEM_STORAGE_STATIC)
              : GRPC_MDNULL;
 }
 
-grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
-    {{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
-     {&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}},
-    {{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
-     {&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}},
-    {{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
-     {&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}},
-    {{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
-     {&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}},
-    {{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
-     {&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}},
-    {{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
-     {&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}},
-    {{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
-     {&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}},
-    {{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
-     {&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}},
-    {{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
-     {&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}},
-    {{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
-     {&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}},
-    {{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
-     {&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}},
-    {{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
-     {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
-    {{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
-     {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
-    {{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
-     {&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
-    {{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
-     {&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}},
-    {{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
-     {&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}},
-    {{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
-     {&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}},
-    {{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
-     {&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}},
-    {{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
-     {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
-    {{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
-     {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
-    {{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
-     {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}},
-    {{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
-     {&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}},
-    {{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
-     {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
-    {{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
-     {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
-    {{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
-     {&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
+grpc_core::StaticMetadata grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
+        {&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
+        {&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
+        {&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
+        {&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
+        {&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
+        {&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
+        {&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
+        {&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
+        {&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
+        {&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
+        {&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
+        {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
+        {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
+        {&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
+        {&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
+        {&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
+        {&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
+        {&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
+        {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
+        {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
+        {&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
+        {&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
+        {&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
+        {&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
+    grpc_core::StaticMetadata(
+        {&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
+        {&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
 };
 const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  76, 77, 78,
                                                          79, 80, 81, 82};
index 88293ae..800ee04 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <cstdint>
+
 #include "src/core/lib/transport/metadata.h"
 
 #define GRPC_STATIC_MDSTR_COUNT 107
@@ -263,271 +265,359 @@ extern grpc_slice_refcount
    (slice).refcount->GetType() == grpc_slice_refcount::Type::STATIC)
 
 #define GRPC_STATIC_METADATA_INDEX(static_slice) \
-  ((int)((static_slice).refcount - grpc_static_metadata_refcounts))
+  (static_cast<intptr_t>(                        \
+      ((static_slice).refcount - grpc_static_metadata_refcounts)))
 
 #define GRPC_STATIC_MDELEM_COUNT 86
-extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+extern grpc_core::StaticMetadata
+    grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
 /* ":authority": "" */
-#define GRPC_MDELEM_AUTHORITY_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_AUTHORITY_EMPTY                      \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":method": "GET" */
-#define GRPC_MDELEM_METHOD_GET \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_METHOD_GET                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":method": "POST" */
-#define GRPC_MDELEM_METHOD_POST \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_METHOD_POST                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_PATH_SLASH                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":scheme": "http" */
-#define GRPC_MDELEM_SCHEME_HTTP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_SCHEME_HTTP                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":scheme": "https" */
-#define GRPC_MDELEM_SCHEME_HTTPS \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_SCHEME_HTTPS                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_200                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "204" */
-#define GRPC_MDELEM_STATUS_204 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_204                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "206" */
-#define GRPC_MDELEM_STATUS_206 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_206                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "304" */
-#define GRPC_MDELEM_STATUS_304 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_304                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "400" */
-#define GRPC_MDELEM_STATUS_400 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_400                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_404                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":status": "500" */
-#define GRPC_MDELEM_STATUS_500 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STATUS_500                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-charset": "" */
-#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY                  \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-encoding": "gzip, deflate" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE    \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-language": "" */
-#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY                 \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-ranges": "" */
-#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept": "" */
-#define GRPC_MDELEM_ACCEPT_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_EMPTY                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "access-control-allow-origin": "" */
-#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY     \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "age": "" */
-#define GRPC_MDELEM_AGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_AGE_EMPTY                             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "allow": "" */
-#define GRPC_MDELEM_ALLOW_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ALLOW_EMPTY                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "authorization": "" */
-#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_AUTHORIZATION_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "cache-control": "" */
-#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CACHE_CONTROL_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-disposition": "" */
-#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-encoding": "" */
-#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY                \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-language": "" */
-#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY                \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-length": "" */
-#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY                  \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-location": "" */
-#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY                \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-range": "" */
-#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_RANGE_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-type": "" */
-#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_TYPE_EMPTY                    \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "cookie": "" */
-#define GRPC_MDELEM_COOKIE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_COOKIE_EMPTY                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "date": "" */
-#define GRPC_MDELEM_DATE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_DATE_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "etag": "" */
-#define GRPC_MDELEM_ETAG_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ETAG_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "expect": "" */
-#define GRPC_MDELEM_EXPECT_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_EXPECT_EMPTY                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "expires": "" */
-#define GRPC_MDELEM_EXPIRES_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_EXPIRES_EMPTY                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "from": "" */
-#define GRPC_MDELEM_FROM_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_FROM_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "host": "" */
-#define GRPC_MDELEM_HOST_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_HOST_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "if-match": "" */
-#define GRPC_MDELEM_IF_MATCH_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_IF_MATCH_EMPTY                        \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "if-modified-since": "" */
-#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY               \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "if-none-match": "" */
-#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "if-range": "" */
-#define GRPC_MDELEM_IF_RANGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_IF_RANGE_EMPTY                        \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "if-unmodified-since": "" */
-#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "last-modified": "" */
-#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_LAST_MODIFIED_EMPTY                   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "link": "" */
-#define GRPC_MDELEM_LINK_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_LINK_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "location": "" */
-#define GRPC_MDELEM_LOCATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_LOCATION_EMPTY                        \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "max-forwards": "" */
-#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_MAX_FORWARDS_EMPTY                    \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "proxy-authenticate": "" */
-#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY              \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "proxy-authorization": "" */
-#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "range": "" */
-#define GRPC_MDELEM_RANGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_RANGE_EMPTY                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "referer": "" */
-#define GRPC_MDELEM_REFERER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_REFERER_EMPTY                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "refresh": "" */
-#define GRPC_MDELEM_REFRESH_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_REFRESH_EMPTY                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "retry-after": "" */
-#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY                     \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "server": "" */
-#define GRPC_MDELEM_SERVER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_SERVER_EMPTY                          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "set-cookie": "" */
-#define GRPC_MDELEM_SET_COOKIE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_SET_COOKIE_EMPTY                      \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "strict-transport-security": "" */
-#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY       \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "transfer-encoding": "" */
-#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY               \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "user-agent": "" */
-#define GRPC_MDELEM_USER_AGENT_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_USER_AGENT_EMPTY                      \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "vary": "" */
-#define GRPC_MDELEM_VARY_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_VARY_EMPTY                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "via": "" */
-#define GRPC_MDELEM_VIA_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_VIA_EMPTY                             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "www-authenticate": "" */
-#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY                \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-status": "0" */
-#define GRPC_MDELEM_GRPC_STATUS_0 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_STATUS_0                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-status": "1" */
-#define GRPC_MDELEM_GRPC_STATUS_1 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_STATUS_1                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-status": "2" */
-#define GRPC_MDELEM_GRPC_STATUS_2 \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_STATUS_2                         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY                \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ENCODING_GZIP                    \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE                 \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_TE_TRAILERS                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-type": "application/grpc" */
-#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_SCHEME_GRPC                           \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* ":method": "PUT" */
-#define GRPC_MDELEM_METHOD_PUT \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_METHOD_PUT                            \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-encoding": "" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY                 \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-encoding": "identity" */
-#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "content-encoding": "gzip" */
-#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_CONTENT_ENCODING_GZIP                 \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "lb-token": "" */
-#define GRPC_MDELEM_LB_TOKEN_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_LB_TOKEN_EMPTY                        \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "lb-cost-bin": "" */
-#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_LB_COST_BIN_EMPTY                     \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY         \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE          \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,deflate" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78].data(),       \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP             \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80].data(),    \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "deflate,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81].data(),   \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,deflate,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82].data(),                  \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-encoding": "identity" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY              \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-encoding": "gzip" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP                  \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 /* "accept-encoding": "identity,gzip" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85], GRPC_MDELEM_STORAGE_STATIC))
+#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP   \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85].data(), \
+                    GRPC_MDELEM_STORAGE_STATIC))
 
-grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);
+grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);
 typedef enum {
   GRPC_BATCH_PATH,
   GRPC_BATCH_METHOD,
@@ -586,22 +676,24 @@ typedef union {
   } named;
 } grpc_metadata_batch_callouts;
 
-#define GRPC_BATCH_INDEX_OF(slice)                      \
-  (GRPC_IS_STATIC_METADATA_STRING((slice))              \
-       ? (grpc_metadata_batch_callouts_index)GPR_CLAMP( \
-             GRPC_STATIC_METADATA_INDEX((slice)), 0,    \
-             GRPC_BATCH_CALLOUTS_COUNT)                 \
+#define GRPC_BATCH_INDEX_OF(slice)                                        \
+  (GRPC_IS_STATIC_METADATA_STRING((slice))                                \
+       ? static_cast<grpc_metadata_batch_callouts_index>(                 \
+             GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0,            \
+                       static_cast<intptr_t>(GRPC_BATCH_CALLOUTS_COUNT))) \
        : GRPC_BATCH_CALLOUTS_COUNT)
 
 extern const uint8_t grpc_static_accept_encoding_metadata[8];
-#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs)                       \
-  (GRPC_MAKE_MDELEM(                                                           \
-      &grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \
+#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs)                      \
+  (GRPC_MAKE_MDELEM(                                                          \
+      &grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]] \
+           .data(),                                                           \
       GRPC_MDELEM_STORAGE_STATIC))
 
 extern const uint8_t grpc_static_accept_stream_encoding_metadata[4];
 #define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs)                \
   (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table                                  \
-                        [grpc_static_accept_stream_encoding_metadata[(algs)]], \
+                         [grpc_static_accept_stream_encoding_metadata[(algs)]] \
+                             .data(),                                          \
                     GRPC_MDELEM_STORAGE_STATIC))
 #endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */
index 29c1e56..80ffabc 100644 (file)
@@ -90,7 +90,7 @@ void grpc_stream_ref_init(grpc_stream_refcount* refcount, int initial_refs,
 #endif
   GRPC_CLOSURE_INIT(&refcount->destroy, cb, cb_arg, grpc_schedule_on_exec_ctx);
 
-  new (&refcount->refs) grpc_core::RefCount();
+  new (&refcount->refs) grpc_core::RefCount(1, &grpc_trace_stream_refcount);
   new (&refcount->slice_refcount) grpc_slice_refcount(
       grpc_slice_refcount::Type::REGULAR, &refcount->refs, slice_stream_destroy,
       refcount, &refcount->slice_refcount);
index a6a6e90..17608f4 100644 (file)
@@ -80,11 +80,13 @@ inline void grpc_stream_ref(grpc_stream_refcount* refcount,
     gpr_log(GPR_DEBUG, "%s %p:%p REF %s", refcount->object_type, refcount,
             refcount->destroy.cb_arg, reason);
   }
+  refcount->refs.RefNonZero(DEBUG_LOCATION, reason);
+}
 #else
 inline void grpc_stream_ref(grpc_stream_refcount* refcount) {
-#endif
   refcount->refs.RefNonZero();
 }
+#endif
 
 void grpc_stream_destroy(grpc_stream_refcount* refcount);
 
@@ -95,13 +97,17 @@ inline void grpc_stream_unref(grpc_stream_refcount* refcount,
     gpr_log(GPR_DEBUG, "%s %p:%p UNREF %s", refcount->object_type, refcount,
             refcount->destroy.cb_arg, reason);
   }
+  if (GPR_UNLIKELY(refcount->refs.Unref(DEBUG_LOCATION, reason))) {
+    grpc_stream_destroy(refcount);
+  }
+}
 #else
 inline void grpc_stream_unref(grpc_stream_refcount* refcount) {
-#endif
   if (GPR_UNLIKELY(refcount->refs.Unref())) {
     grpc_stream_destroy(refcount);
   }
 }
+#endif
 
 /* Wrap a buffer that is owned by some stream object into a slice that shares
    the same refcount */
index 8ae0089..d8638e7 100644 (file)
@@ -48,7 +48,7 @@ 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
+ * shared by all TSI handshakes. The application is responsible for
  * invoking the API before calling grpc_shutdown().
  */
 void grpc_alts_shared_resource_dedicated_shutdown();
index 58f012d..de0f4e1 100644 (file)
@@ -42,8 +42,7 @@
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/surface/completion_queue.h"
 
-void grpc::experimental::ChannelResetConnectionBackoff(
-    ::grpc::Channel* channel) {
+void ::grpc::experimental::ChannelResetConnectionBackoff(Channel* channel) {
   grpc_impl::experimental::ChannelResetConnectionBackoff(channel);
 }
 
@@ -145,7 +144,7 @@ void ChannelResetConnectionBackoff(Channel* channel) {
 
   // 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/
+  // should notify the interceptors too.
   auto* info =
       context->set_client_rpc_info(method.name(), method.method_type(), this,
                                    interceptor_creators_, interceptor_pos);
@@ -156,7 +155,7 @@ void ChannelResetConnectionBackoff(Channel* channel) {
 
 ::grpc::internal::Call Channel::CreateCall(
     const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
-    ::grpc::CompletionQueue* cq) {
+    CompletionQueue* cq) {
   return CreateCallInternal(method, context, cq, 0);
 }
 
index 0ae1ecb..efb10a4 100644 (file)
@@ -34,9 +34,6 @@
 namespace grpc_impl {
 
 class Channel;
-}
-
-namespace grpc {
 
 class DefaultGlobalClientCallbacks final
     : public ClientContext::GlobalCallbacks {
@@ -46,7 +43,7 @@ class DefaultGlobalClientCallbacks final
   void Destructor(ClientContext* context) override {}
 };
 
-static internal::GrpcLibraryInitializer g_gli_initializer;
+static grpc::internal::GrpcLibraryInitializer g_gli_initializer;
 static DefaultGlobalClientCallbacks* g_default_client_callbacks =
     new DefaultGlobalClientCallbacks();
 static ClientContext::GlobalCallbacks* g_client_callbacks =
@@ -76,7 +73,7 @@ ClientContext::~ClientContext() {
 }
 
 std::unique_ptr<ClientContext> ClientContext::FromServerContext(
-    const ServerContext& context, PropagationOptions options) {
+    const grpc::ServerContext& context, PropagationOptions options) {
   std::unique_ptr<ClientContext> ctx(new ClientContext);
   ctx->propagate_from_call_ = context.call_;
   ctx->propagation_options_ = options;
@@ -130,7 +127,7 @@ void ClientContext::TryCancel() {
 }
 
 void ClientContext::SendCancelToInterceptors() {
-  internal::CancelInterceptorBatchMethods cancel_methods;
+  grpc::internal::CancelInterceptorBatchMethods cancel_methods;
   for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) {
     rpc_info_.RunInterceptor(&cancel_methods, i);
   }
@@ -153,4 +150,4 @@ void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
   g_client_callbacks = client_callbacks;
 }
 
-}  // namespace grpc
+}  // namespace grpc_impl
index 3318ded..ca7038b 100644 (file)
@@ -71,7 +71,7 @@ std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
         interceptor_creators) {
   return creds ? creds->CreateChannelWithInterceptors(
                      target, args, std::move(interceptor_creators))
-               : ::grpc::CreateChannelInternal(
+               : grpc::CreateChannelInternal(
                      "",
                      grpc_lame_client_channel_create(
                          nullptr, GRPC_STATUS_INVALID_ARGUMENT,
index 724a43a..197112d 100644 (file)
@@ -22,6 +22,8 @@
 #include <grpcpp/channel.h>
 #include <grpcpp/impl/grpc_library.h>
 #include <grpcpp/support/channel_arguments.h>
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/security/transport/auth_filters.h"
 #include "src/cpp/client/create_channel_internal.h"
 #include "src/cpp/common/secure_auth_context.h"
 
@@ -223,13 +225,23 @@ std::shared_ptr<grpc_impl::CallCredentials> MetadataCredentialsFromPlugin(
 }  // namespace grpc_impl
 
 namespace grpc {
-
-void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
-  if (wrapper == nullptr) return;
+namespace {
+void DeleteWrapper(void* wrapper, grpc_error* ignored) {
   MetadataCredentialsPluginWrapper* w =
       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
   delete w;
 }
+}  // namespace
+
+void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
+  if (wrapper == nullptr) return;
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
+  GRPC_CLOSURE_RUN(GRPC_CLOSURE_CREATE(DeleteWrapper, wrapper,
+                                       grpc_core::Executor::Scheduler(
+                                           grpc_core::ExecutorJobType::SHORT)),
+                   GRPC_ERROR_NONE);
+}
 
 int MetadataCredentialsPluginWrapper::GetMetadata(
     void* wrapper, grpc_auth_metadata_context context,
@@ -247,10 +259,15 @@ int MetadataCredentialsPluginWrapper::GetMetadata(
     return true;
   }
   if (w->plugin_->IsBlocking()) {
+    // The internals of context may be destroyed if GetMetadata is cancelled.
+    // Make a copy for InvokePlugin.
+    grpc_auth_metadata_context context_copy = grpc_auth_metadata_context();
+    grpc_auth_metadata_context_copy(&context, &context_copy);
     // Asynchronous return.
-    w->thread_pool_->Add([w, context, cb, user_data] {
+    w->thread_pool_->Add([w, context_copy, cb, user_data]() mutable {
       w->MetadataCredentialsPluginWrapper::InvokePlugin(
-          context, cb, user_data, nullptr, nullptr, nullptr, nullptr);
+          context_copy, cb, user_data, nullptr, nullptr, nullptr, nullptr);
+      grpc_auth_metadata_context_reset(&context_copy);
     });
     return 0;
   } else {
index 422e7bb..8df6c7b 100644 (file)
@@ -30,7 +30,6 @@ namespace grpc {
 grpc_linked_mdelem* MetadataBatch::AddMetadata(const string& key,
                                                const string& value) {
   grpc_linked_mdelem* storage = new grpc_linked_mdelem;
-  memset(storage, 0, sizeof(grpc_linked_mdelem));
   storage->md = grpc_mdelem_from_slices(SliceFromCopiedString(key),
                                         SliceFromCopiedString(value));
   GRPC_LOG_IF_ERROR("MetadataBatch::AddMetadata",
diff --git a/src/cpp/common/validate_service_config.cc b/src/cpp/common/validate_service_config.cc
new file mode 100644 (file)
index 0000000..0f193cf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2019 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 <grpcpp/support/validate_service_config.h>
+
+#include "src/core/ext/filters/client_channel/service_config.h"
+
+namespace grpc {
+namespace experimental {
+grpc::string ValidateServiceConfigJSON(
+    const grpc::string& service_config_json) {
+  grpc_init();
+  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_core::ServiceConfig::Create(service_config_json.c_str(), &error);
+  grpc::string return_value;
+  if (error != GRPC_ERROR_NONE) {
+    return_value = grpc_error_string(error);
+    GRPC_ERROR_UNREF(error);
+  }
+  grpc_shutdown();
+  return return_value;
+}
+}  // namespace experimental
+}  // namespace grpc
index 98c1ba3..c04c12b 100644 (file)
@@ -22,5 +22,5 @@
 #include <grpcpp/grpcpp.h>
 
 namespace grpc {
-grpc::string Version() { return "1.21.3"; }
+grpc::string Version() { return "1.22.0"; }
 }  // namespace grpc
index 993faae..1317675 100644 (file)
 #include "include/grpcpp/opencensus.h"
 #include "opencensus/stats/stats.h"
 
-namespace grpc {
+namespace grpc_impl {
 class ServerContext;
+}
+
+namespace grpc {
 
 // The tag keys set when recording RPC stats.
 ::opencensus::stats::TagKey ClientMethodTagKey();
diff --git a/src/cpp/server/external_connection_acceptor_impl.cc b/src/cpp/server/external_connection_acceptor_impl.cc
new file mode 100644 (file)
index 0000000..7f0e2dc
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2019 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/cpp/server/external_connection_acceptor_impl.h"
+
+#include <memory>
+
+#include <grpcpp/server_builder_impl.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+namespace internal {
+namespace {
+// The actual type to return to user. It co-owns the internal impl object with
+// the server.
+class AcceptorWrapper : public experimental::ExternalConnectionAcceptor {
+ public:
+  explicit AcceptorWrapper(std::shared_ptr<ExternalConnectionAcceptorImpl> impl)
+      : impl_(std::move(impl)) {}
+  void HandleNewConnection(NewConnectionParameters* p) override {
+    impl_->HandleNewConnection(p);
+  }
+
+ private:
+  std::shared_ptr<ExternalConnectionAcceptorImpl> impl_;
+};
+}  // namespace
+
+ExternalConnectionAcceptorImpl::ExternalConnectionAcceptorImpl(
+    const grpc::string& name,
+    ServerBuilder::experimental_type::ExternalConnectionType type,
+    std::shared_ptr<ServerCredentials> creds)
+    : name_(name), creds_(std::move(creds)) {
+  GPR_ASSERT(type ==
+             ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD);
+}
+
+std::unique_ptr<experimental::ExternalConnectionAcceptor>
+ExternalConnectionAcceptorImpl::GetAcceptor() {
+  std::lock_guard<std::mutex> lock(mu_);
+  GPR_ASSERT(!has_acceptor_);
+  has_acceptor_ = true;
+  return std::unique_ptr<experimental::ExternalConnectionAcceptor>(
+      new AcceptorWrapper(shared_from_this()));
+}
+
+void ExternalConnectionAcceptorImpl::HandleNewConnection(
+    experimental::ExternalConnectionAcceptor::NewConnectionParameters* p) {
+  std::lock_guard<std::mutex> lock(mu_);
+  if (shutdown_ || !started_) {
+    // TODO(yangg) clean up.
+    gpr_log(
+        GPR_ERROR,
+        "NOT handling external connection with fd %d, started %d, shutdown %d",
+        p->fd, started_, shutdown_);
+    return;
+  }
+  if (handler_) {
+    handler_->Handle(p->listener_fd, p->fd, p->read_buffer.c_buffer());
+  }
+}
+
+void ExternalConnectionAcceptorImpl::Shutdown() {
+  std::lock_guard<std::mutex> lock(mu_);
+  shutdown_ = true;
+}
+
+void ExternalConnectionAcceptorImpl::Start() {
+  std::lock_guard<std::mutex> lock(mu_);
+  GPR_ASSERT(!started_);
+  GPR_ASSERT(has_acceptor_);
+  GPR_ASSERT(!shutdown_);
+  started_ = true;
+}
+
+void ExternalConnectionAcceptorImpl::SetToChannelArgs(ChannelArguments* args) {
+  args->SetPointer(name_.c_str(), &handler_);
+}
+
+}  // namespace internal
+}  // namespace grpc
diff --git a/src/cpp/server/external_connection_acceptor_impl.h b/src/cpp/server/external_connection_acceptor_impl.h
new file mode 100644 (file)
index 0000000..b5bd935
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2019 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 SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_
+#define SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_
+
+#include <memory>
+#include <mutex>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/security/server_credentials_impl.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/support/channel_arguments.h>
+
+#include "src/core/lib/iomgr/tcp_server.h"
+
+namespace grpc {
+namespace internal {
+
+class ExternalConnectionAcceptorImpl
+    : public std::enable_shared_from_this<ExternalConnectionAcceptorImpl> {
+ public:
+  ExternalConnectionAcceptorImpl(
+      const grpc::string& name,
+      ServerBuilder::experimental_type::ExternalConnectionType type,
+      std::shared_ptr<ServerCredentials> creds);
+  // Should only be called once.
+  std::unique_ptr<experimental::ExternalConnectionAcceptor> GetAcceptor();
+
+  void HandleNewConnection(
+      experimental::ExternalConnectionAcceptor::NewConnectionParameters* p);
+
+  void Shutdown();
+
+  void Start();
+
+  const char* name() { return name_.c_str(); }
+
+  ServerCredentials* GetCredentials() { return creds_.get(); }
+
+  void SetToChannelArgs(::grpc::ChannelArguments* args);
+
+ private:
+  const grpc::string name_;
+  std::shared_ptr<ServerCredentials> creds_;
+  grpc_core::TcpServerFdHandler* handler_ = nullptr;  // not owned
+  std::mutex mu_;
+  bool has_acceptor_ = false;
+  bool started_ = false;
+  bool shutdown_ = false;
+};
+
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_
index af76ffb..1ba9ae1 100644 (file)
@@ -26,7 +26,9 @@
 
 #include <utility>
 
+#include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/cpp/server/external_connection_acceptor_impl.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc_impl {
@@ -114,6 +116,19 @@ ServerBuilder& ServerBuilder::experimental_type::RegisterCallbackGenericService(
   return *builder_;
 }
 
+std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
+ServerBuilder::experimental_type::AddExternalConnectionAcceptor(
+    experimental_type::ExternalConnectionType type,
+    std::shared_ptr<ServerCredentials> creds) {
+  grpc::string name_prefix("external:");
+  char count_str[GPR_LTOA_MIN_BUFSIZE];
+  gpr_ltoa(static_cast<long>(builder_->acceptors_.size()), count_str);
+  builder_->acceptors_.emplace_back(
+      std::make_shared<grpc::internal::ExternalConnectionAcceptorImpl>(
+          name_prefix.append(count_str), type, creds));
+  return builder_->acceptors_.back()->GetAcceptor();
+}
+
 ServerBuilder& ServerBuilder::SetOption(
     std::unique_ptr<grpc::ServerBuilderOption> option) {
   options_.push_back(std::move(option));
@@ -307,8 +322,8 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
   std::unique_ptr<grpc::Server> server(new grpc::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_)));
+      sync_server_settings_.cq_timeout_msec, std::move(acceptors_),
+      resource_quota_, std::move(interceptor_creators_)));
 
   grpc_impl::ServerInitializer* initializer = server->initializer();
 
index 9c2b1ee..02cfb59 100644 (file)
@@ -28,6 +28,7 @@
 #include <grpcpp/completion_queue.h>
 #include <grpcpp/generic/async_generic_service.h>
 #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/completion_queue_tag.h>
 #include <grpcpp/impl/codegen/server_interceptor.h>
@@ -46,6 +47,7 @@
 #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/external_connection_acceptor_impl.h"
 #include "src/cpp/server/health/default_health_check_service.h"
 #include "src/cpp/thread_manager/thread_manager.h"
 
@@ -936,11 +938,14 @@ Server::Server(
     std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
         sync_server_cqs,
     int min_pollers, int max_pollers, int sync_cq_timeout_msec,
+    std::vector<std::shared_ptr<grpc::internal::ExternalConnectionAcceptorImpl>>
+        acceptors,
     grpc_resource_quota* server_rq,
     std::vector<
         std::unique_ptr<grpc::experimental::ServerInterceptorFactoryInterface>>
         interceptor_creators)
-    : interceptor_creators_(std::move(interceptor_creators)),
+    : acceptors_(std::move(acceptors)),
+      interceptor_creators_(std::move(interceptor_creators)),
       max_receive_message_size_(max_receive_message_size),
       sync_server_cqs_(std::move(sync_server_cqs)),
       started_(false),
@@ -974,6 +979,10 @@ Server::Server(
     }
   }
 
+  for (auto& acceptor : acceptors_) {
+    acceptor->SetToChannelArgs(args);
+  }
+
   grpc_channel_args channel_args;
   args->SetChannelArgs(&channel_args);
 
@@ -1188,6 +1197,10 @@ void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
     RegisterService(nullptr, default_health_check_service_impl);
   }
 
+  for (auto& acceptor : acceptors_) {
+    acceptor->GetCredentials()->AddPortToServer(acceptor->name(), server_);
+  }
+
   // If this server uses callback methods, then create a callback generic
   // service to handle any unimplemented methods using the default reactor
   // creator
@@ -1234,6 +1247,10 @@ void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
   if (default_health_check_service_impl != nullptr) {
     default_health_check_service_impl->StartServingThread();
   }
+
+  for (auto& acceptor : acceptors_) {
+    acceptor->Start();
+  }
 }
 
 void Server::ShutdownInternal(gpr_timespec deadline) {
@@ -1244,6 +1261,10 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
 
   shutdown_ = true;
 
+  for (auto& acceptor : acceptors_) {
+    acceptor->Shutdown();
+  }
+
   /// The completion queue to use for server shutdown completion notification
   grpc::CompletionQueue shutdown_cq;
   grpc::ShutdownTag shutdown_tag;  // Dummy shutdown tag
index eced89d..ba83423 100644 (file)
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpcpp/server_context.h>
+#include <grpcpp/impl/codegen/server_context_impl.h>
 #include <grpcpp/support/server_callback.h>
 
 #include <algorithm>
 #include <grpc/load_reporting.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpcpp/completion_queue.h>
 #include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/completion_queue_impl.h>
 #include <grpcpp/support/time.h>
 
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/surface/call.h"
 
-namespace grpc {
+namespace grpc_impl {
 
 // CompletionOp
 
-class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
+class ServerContext::CompletionOp final
+    : public ::grpc::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(internal::Call* call, internal::ServerReactor* reactor)
+  CompletionOp(::grpc::internal::Call* call,
+               ::grpc::internal::ServerReactor* reactor)
       : call_(*call),
         reactor_(reactor),
         has_tag_(false),
@@ -67,7 +69,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
     }
   }
 
-  void FillOps(internal::Call* call) override;
+  void FillOps(::grpc::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
@@ -149,8 +151,8 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
     return finalized_ ? (cancelled_ != 0) : false;
   }
 
-  internal::Call call_;
-  internal::ServerReactor* const reactor_;
+  ::grpc::internal::Call call_;
+  ::grpc::internal::ServerReactor* const reactor_;
   bool has_tag_;
   void* tag_;
   void* core_cq_tag_;
@@ -160,7 +162,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
   int cancelled_;  // This is an int (not bool) because it is passed to core
   std::function<void()> cancel_callback_;
   bool done_intercepting_;
-  internal::InterceptorBatchMethodsImpl interceptor_methods_;
+  ::grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
 };
 
 void ServerContext::CompletionOp::Unref() {
@@ -171,7 +173,7 @@ void ServerContext::CompletionOp::Unref() {
   }
 }
 
-void ServerContext::CompletionOp::FillOps(internal::Call* call) {
+void ServerContext::CompletionOp::FillOps(::grpc::internal::Call* call) {
   grpc_op ops;
   ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   ops.data.recv_close_on_server.cancelled = &cancelled_;
@@ -227,7 +229,7 @@ bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
   }
   /* Add interception point and run through interceptors */
   interceptor_methods_.AddInterceptionHookPoint(
-      experimental::InterceptionHookPoints::POST_RECV_CLOSE);
+      ::grpc::experimental::InterceptionHookPoints::POST_RECV_CLOSE);
   if (interceptor_methods_.RunInterceptors()) {
     /* No interceptors were run */
     if (has_tag_) {
@@ -292,9 +294,9 @@ void ServerContext::Clear() {
   }
 }
 
-void ServerContext::BeginCompletionOp(internal::Call* call,
-                                      std::function<void(bool)> callback,
-                                      internal::ServerReactor* reactor) {
+void ServerContext::BeginCompletionOp(
+    ::grpc::internal::Call* call, std::function<void(bool)> callback,
+    ::grpc::internal::ServerReactor* reactor) {
   GPR_ASSERT(!completion_op_);
   if (rpc_info_) {
     rpc_info_->Ref();
@@ -313,8 +315,8 @@ void ServerContext::BeginCompletionOp(internal::Call* call,
   call->PerformOps(completion_op_);
 }
 
-internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() {
-  return static_cast<internal::CompletionQueueTag*>(completion_op_);
+::grpc::internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() {
+  return static_cast<::grpc::internal::CompletionQueueTag*>(completion_op_);
 }
 
 void ServerContext::AddInitialMetadata(const grpc::string& key,
@@ -328,7 +330,7 @@ void ServerContext::AddTrailingMetadata(const grpc::string& key,
 }
 
 void ServerContext::TryCancel() const {
-  internal::CancelInterceptorBatchMethods cancel_methods;
+  ::grpc::internal::CancelInterceptorBatchMethods cancel_methods;
   if (rpc_info_) {
     for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) {
       rpc_info_->RunInterceptor(&cancel_methods, i);
@@ -398,4 +400,4 @@ void ServerContext::SetLoadReportingCosts(
   }
 }
 
-}  // namespace grpc
+}  // namespace grpc_impl
index 2fbf309..62b1bee 100644 (file)
@@ -56,7 +56,7 @@ class ThreadManager {
   //    DoWork()
   //
   // If the return value is SHUTDOWN:,
-  //  - ThreadManager WILL NOT call DoWork() and terminates the thead
+  //  - ThreadManager WILL NOT call DoWork() and terminates the thread
   //
   // If the return value is TIMEOUT:,
   //  - ThreadManager WILL NOT call DoWork()
@@ -133,7 +133,7 @@ class ThreadManager {
     grpc_core::Thread thd_;
   };
 
-  // The main funtion in ThreadManager
+  // The main function in ThreadManager
   void MainWorkLoop();
 
   void MarkAsCompleted(WorkerThread* thd);
index 3addc24..400365a 100644 (file)
@@ -355,3 +355,24 @@ Unless explicitly set, will follow `OutputDir` for any given file.
 
 * __Access__  
 Sets generated class access on _both_ generated message and gRPC stub classes.
+
+`grpc_csharp_plugin` command line options
+---------
+
+Under the hood, the `Grpc.Tools` build integration invokes the `protoc` and `grpc_csharp_plugin` binaries
+to perform code generation. Here is an overview of the available `grpc_csharp_plugin` options:
+
+| Name            | Default   | Synopsis                                                 |
+|---------------- |-----------|----------------------------------------------------------|
+| no_client       | off       | Don't generate the client stub                           |
+| no_server       | off       | Don't generate the server-side stub                      |
+| internal_access | off       | Generate classes with "internal" visibility              |
+| lite_client     | off       | Generate client stubs that inherit from "LiteClientBase" |
+
+Note that the protocol buffer compiler has a special commandline syntax for plugin options.
+Example:
+```
+protoc --plugin=protoc-gen-grpc=grpc_csharp_plugin --csharp_out=OUT_DIR \
+    --grpc_out=OUT_DIR --grpc_opt=lite_client,no_server \
+    -I INCLUDE_DIR foo.proto
+```
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Api/LiteClientBase.cs b/src/csharp/Grpc.Core.Api/LiteClientBase.cs
new file mode 100644 (file)
index 0000000..c3215f0
--- /dev/null
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+
+// Copyright 2019 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 Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+    /// <summary>
+    /// Base class for lightweight client-side stubs.
+    /// All calls are invoked via a <c>CallInvoker</c>.
+    /// Lite client stubs have no configuration knobs, all configuration
+    /// is provided by decorating the call invoker.
+    /// Note: experimental API that can change or be removed without any prior notice.
+    /// </summary>
+    public abstract class LiteClientBase
+    {
+        readonly CallInvoker callInvoker;
+
+        /// <summary>
+        /// Initializes a new instance of <c>LiteClientBase</c> class that
+        /// throws <c>NotImplementedException</c> upon invocation of any RPC.
+        /// This constructor is only provided to allow creation of test doubles
+        /// for client classes (e.g. mocking requires a parameterless constructor).
+        /// </summary>
+        protected LiteClientBase() : this(new UnimplementedCallInvoker())
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of <c>ClientBase</c> class.
+        /// </summary>
+        /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param>
+        public LiteClientBase(CallInvoker callInvoker)
+        {
+            this.callInvoker = GrpcPreconditions.CheckNotNull(callInvoker, nameof(callInvoker));
+        }
+
+        /// <summary>
+        /// Gets the call invoker.
+        /// </summary>
+        protected CallInvoker CallInvoker
+        {
+            get { return this.callInvoker; }
+        }
+
+        /// <summary>
+        /// Call invoker that throws <c>NotImplementedException</c> for all requests.
+        /// </summary>
+        private class UnimplementedCallInvoker : CallInvoker
+        {
+            public UnimplementedCallInvoker()
+            {
+            }
+
+            public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+            {
+                throw new NotImplementedException();
+            }
+
+            public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+            {
+                throw new NotImplementedException();
+            }
+
+            public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+            {
+                throw new NotImplementedException();
+            }
+
+            public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+            {
+                throw new NotImplementedException();
+            }
+
+            public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+            {
+                throw new NotImplementedException();
+            }
+        }
+    }
+}
index 3d4bdd9..40ad442 100644 (file)
@@ -33,11 +33,11 @@ namespace Grpc.Core
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.21.3.0";
+        public const string CurrentAssemblyFileVersion = "1.22.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.21.3";
+        public const string CurrentVersion = "1.22.0";
     }
 }
index ab5f5a8..fb99cfc 100644 (file)
@@ -36,6 +36,7 @@ using Grpc.Core.Utils;
 [assembly:TypeForwardedToAttribute(typeof(CallCredentials))]
 [assembly:TypeForwardedToAttribute(typeof(CallFlags))]
 [assembly:TypeForwardedToAttribute(typeof(CallInvoker))]
+[assembly:TypeForwardedToAttribute(typeof(CallInvokerExtensions))]
 [assembly:TypeForwardedToAttribute(typeof(CallOptions))]
 [assembly:TypeForwardedToAttribute(typeof(ClientInterceptorContext<,>))]
 [assembly:TypeForwardedToAttribute(typeof(ContextPropagationOptions))]
@@ -45,6 +46,7 @@ using Grpc.Core.Utils;
 [assembly:TypeForwardedToAttribute(typeof(IAsyncStreamWriter<>))]
 [assembly:TypeForwardedToAttribute(typeof(IClientStreamWriter<>))]
 [assembly:TypeForwardedToAttribute(typeof(Interceptor))]
+[assembly:TypeForwardedToAttribute(typeof(InterceptingCallInvoker))]
 [assembly:TypeForwardedToAttribute(typeof(IServerStreamWriter<>))]
 [assembly:TypeForwardedToAttribute(typeof(Marshaller<>))]
 [assembly:TypeForwardedToAttribute(typeof(Marshallers))]
index 8e4e44b..d0fc600 100644 (file)
@@ -103,7 +103,7 @@ namespace Grpc.Core
         /// <summary>
         /// Server requests client certificate and enforces that the client presents a
         /// certificate.
-        /// The cerificate presented by the client is verified by the gRPC framework.
+        /// The certificate presented by the client is verified by the gRPC framework.
         /// (For a successful connection the client needs to present a certificate that
         /// can be verified against the root certificate configured by the server)
         /// The client's key certificate pair must be valid for the SSL connection to
index 6354a05..e24afda 100755 (executable)
@@ -2,6 +2,6 @@
 <Project>
   <PropertyGroup>
     <GrpcCsharpVersion>1.19.1</GrpcCsharpVersion>
-    <GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
+    <GoogleProtobufVersion>3.8.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Examples/MathWithProtocOptions.cs b/src/csharp/Grpc.Examples/MathWithProtocOptions.cs
new file mode 100644 (file)
index 0000000..ef9a5a4
--- /dev/null
@@ -0,0 +1,759 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: math_with_protoc_options.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 MathWithProtocOptions {
+
+  /// <summary>Holder for reflection information generated from math_with_protoc_options.proto</summary>
+  public static partial class MathWithProtocOptionsReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for math_with_protoc_options.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static MathWithProtocOptionsReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5tYXRoX3dpdGhfcHJvdG9jX29wdGlvbnMucHJvdG8SGG1hdGhfd2l0aF9w",
+            "cm90b2Nfb3B0aW9ucyIsCgdEaXZBcmdzEhAKCGRpdmlkZW5kGAEgASgDEg8K",
+            "B2Rpdmlzb3IYAiABKAMiLwoIRGl2UmVwbHkSEAoIcXVvdGllbnQYASABKAMS",
+            "EQoJcmVtYWluZGVyGAIgASgDIhgKB0ZpYkFyZ3MSDQoFbGltaXQYASABKAMi",
+            "EgoDTnVtEgsKA251bRgBIAEoAyIZCghGaWJSZXBseRINCgVjb3VudBgBIAEo",
+            "AzLEAgoETWF0aBJOCgNEaXYSIS5tYXRoX3dpdGhfcHJvdG9jX29wdGlvbnMu",
+            "RGl2QXJncxoiLm1hdGhfd2l0aF9wcm90b2Nfb3B0aW9ucy5EaXZSZXBseSIA",
+            "ElYKB0Rpdk1hbnkSIS5tYXRoX3dpdGhfcHJvdG9jX29wdGlvbnMuRGl2QXJn",
+            "cxoiLm1hdGhfd2l0aF9wcm90b2Nfb3B0aW9ucy5EaXZSZXBseSIAKAEwARJL",
+            "CgNGaWISIS5tYXRoX3dpdGhfcHJvdG9jX29wdGlvbnMuRmliQXJncxodLm1h",
+            "dGhfd2l0aF9wcm90b2Nfb3B0aW9ucy5OdW0iADABEkcKA1N1bRIdLm1hdGhf",
+            "d2l0aF9wcm90b2Nfb3B0aW9ucy5OdW0aHS5tYXRoX3dpdGhfcHJvdG9jX29w",
+            "dGlvbnMuTnVtIgAoAWIGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::MathWithProtocOptions.DivArgs), global::MathWithProtocOptions.DivArgs.Parser, new[]{ "Dividend", "Divisor" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MathWithProtocOptions.DivReply), global::MathWithProtocOptions.DivReply.Parser, new[]{ "Quotient", "Remainder" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MathWithProtocOptions.FibArgs), global::MathWithProtocOptions.FibArgs.Parser, new[]{ "Limit" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MathWithProtocOptions.Num), global::MathWithProtocOptions.Num.Parser, new[]{ "Num_" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MathWithProtocOptions.FibReply), global::MathWithProtocOptions.FibReply.Parser, new[]{ "Count" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class DivArgs : pb::IMessage<DivArgs> {
+    private static readonly pb::MessageParser<DivArgs> _parser = new pb::MessageParser<DivArgs>(() => new DivArgs());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<DivArgs> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivArgs() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivArgs(DivArgs other) : this() {
+      dividend_ = other.dividend_;
+      divisor_ = other.divisor_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivArgs Clone() {
+      return new DivArgs(this);
+    }
+
+    /// <summary>Field number for the "dividend" field.</summary>
+    public const int DividendFieldNumber = 1;
+    private long dividend_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Dividend {
+      get { return dividend_; }
+      set {
+        dividend_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "divisor" field.</summary>
+    public const int DivisorFieldNumber = 2;
+    private long divisor_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Divisor {
+      get { return divisor_; }
+      set {
+        divisor_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as DivArgs);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(DivArgs other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Dividend != other.Dividend) return false;
+      if (Divisor != other.Divisor) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Dividend != 0L) hash ^= Dividend.GetHashCode();
+      if (Divisor != 0L) hash ^= Divisor.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 (Dividend != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Dividend);
+      }
+      if (Divisor != 0L) {
+        output.WriteRawTag(16);
+        output.WriteInt64(Divisor);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Dividend != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Dividend);
+      }
+      if (Divisor != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Divisor);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(DivArgs other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Dividend != 0L) {
+        Dividend = other.Dividend;
+      }
+      if (other.Divisor != 0L) {
+        Divisor = other.Divisor;
+      }
+      _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: {
+            Dividend = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Divisor = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public sealed partial class DivReply : pb::IMessage<DivReply> {
+    private static readonly pb::MessageParser<DivReply> _parser = new pb::MessageParser<DivReply>(() => new DivReply());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<DivReply> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivReply() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivReply(DivReply other) : this() {
+      quotient_ = other.quotient_;
+      remainder_ = other.remainder_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public DivReply Clone() {
+      return new DivReply(this);
+    }
+
+    /// <summary>Field number for the "quotient" field.</summary>
+    public const int QuotientFieldNumber = 1;
+    private long quotient_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Quotient {
+      get { return quotient_; }
+      set {
+        quotient_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "remainder" field.</summary>
+    public const int RemainderFieldNumber = 2;
+    private long remainder_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Remainder {
+      get { return remainder_; }
+      set {
+        remainder_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as DivReply);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(DivReply other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Quotient != other.Quotient) return false;
+      if (Remainder != other.Remainder) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Quotient != 0L) hash ^= Quotient.GetHashCode();
+      if (Remainder != 0L) hash ^= Remainder.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 (Quotient != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Quotient);
+      }
+      if (Remainder != 0L) {
+        output.WriteRawTag(16);
+        output.WriteInt64(Remainder);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Quotient != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Quotient);
+      }
+      if (Remainder != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Remainder);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(DivReply other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Quotient != 0L) {
+        Quotient = other.Quotient;
+      }
+      if (other.Remainder != 0L) {
+        Remainder = other.Remainder;
+      }
+      _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: {
+            Quotient = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Remainder = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public sealed partial class FibArgs : pb::IMessage<FibArgs> {
+    private static readonly pb::MessageParser<FibArgs> _parser = new pb::MessageParser<FibArgs>(() => new FibArgs());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<FibArgs> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibArgs() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibArgs(FibArgs other) : this() {
+      limit_ = other.limit_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibArgs Clone() {
+      return new FibArgs(this);
+    }
+
+    /// <summary>Field number for the "limit" field.</summary>
+    public const int LimitFieldNumber = 1;
+    private long limit_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Limit {
+      get { return limit_; }
+      set {
+        limit_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as FibArgs);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(FibArgs other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Limit != other.Limit) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Limit != 0L) hash ^= Limit.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 (Limit != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Limit);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Limit != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Limit);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(FibArgs other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Limit != 0L) {
+        Limit = other.Limit;
+      }
+      _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: {
+            Limit = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public sealed partial class Num : pb::IMessage<Num> {
+    private static readonly pb::MessageParser<Num> _parser = new pb::MessageParser<Num>(() => new Num());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<Num> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Num() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Num(Num other) : this() {
+      num_ = other.num_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Num Clone() {
+      return new Num(this);
+    }
+
+    /// <summary>Field number for the "num" field.</summary>
+    public const int Num_FieldNumber = 1;
+    private long num_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Num_ {
+      get { return num_; }
+      set {
+        num_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as Num);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(Num other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Num_ != other.Num_) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Num_ != 0L) hash ^= Num_.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 (Num_ != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Num_);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Num_ != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Num_);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(Num other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Num_ != 0L) {
+        Num_ = other.Num_;
+      }
+      _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: {
+            Num_ = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public sealed partial class FibReply : pb::IMessage<FibReply> {
+    private static readonly pb::MessageParser<FibReply> _parser = new pb::MessageParser<FibReply>(() => new FibReply());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<FibReply> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibReply() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibReply(FibReply other) : this() {
+      count_ = other.count_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FibReply Clone() {
+      return new FibReply(this);
+    }
+
+    /// <summary>Field number for the "count" field.</summary>
+    public const int CountFieldNumber = 1;
+    private long count_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public long Count {
+      get { return count_; }
+      set {
+        count_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as FibReply);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(FibReply other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Count != other.Count) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Count != 0L) hash ^= Count.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 (Count != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Count);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Count != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(FibReply other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Count != 0L) {
+        Count = other.Count;
+      }
+      _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: {
+            Count = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.Examples/MathWithProtocOptionsGrpc.cs b/src/csharp/Grpc.Examples/MathWithProtocOptionsGrpc.cs
new file mode 100644 (file)
index 0000000..dd61b72
--- /dev/null
@@ -0,0 +1,208 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: math_with_protoc_options.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 MathWithProtocOptions {
+  public static partial class Math
+  {
+    static readonly string __ServiceName = "math_with_protoc_options.Math";
+
+    static readonly grpc::Marshaller<global::MathWithProtocOptions.DivArgs> __Marshaller_math_with_protoc_options_DivArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::MathWithProtocOptions.DivArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::MathWithProtocOptions.DivReply> __Marshaller_math_with_protoc_options_DivReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::MathWithProtocOptions.DivReply.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::MathWithProtocOptions.FibArgs> __Marshaller_math_with_protoc_options_FibArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::MathWithProtocOptions.FibArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::MathWithProtocOptions.Num> __Marshaller_math_with_protoc_options_Num = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::MathWithProtocOptions.Num.Parser.ParseFrom);
+
+    static readonly grpc::Method<global::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply> __Method_Div = new grpc::Method<global::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply>(
+        grpc::MethodType.Unary,
+        __ServiceName,
+        "Div",
+        __Marshaller_math_with_protoc_options_DivArgs,
+        __Marshaller_math_with_protoc_options_DivReply);
+
+    static readonly grpc::Method<global::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply> __Method_DivMany = new grpc::Method<global::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply>(
+        grpc::MethodType.DuplexStreaming,
+        __ServiceName,
+        "DivMany",
+        __Marshaller_math_with_protoc_options_DivArgs,
+        __Marshaller_math_with_protoc_options_DivReply);
+
+    static readonly grpc::Method<global::MathWithProtocOptions.FibArgs, global::MathWithProtocOptions.Num> __Method_Fib = new grpc::Method<global::MathWithProtocOptions.FibArgs, global::MathWithProtocOptions.Num>(
+        grpc::MethodType.ServerStreaming,
+        __ServiceName,
+        "Fib",
+        __Marshaller_math_with_protoc_options_FibArgs,
+        __Marshaller_math_with_protoc_options_Num);
+
+    static readonly grpc::Method<global::MathWithProtocOptions.Num, global::MathWithProtocOptions.Num> __Method_Sum = new grpc::Method<global::MathWithProtocOptions.Num, global::MathWithProtocOptions.Num>(
+        grpc::MethodType.ClientStreaming,
+        __ServiceName,
+        "Sum",
+        __Marshaller_math_with_protoc_options_Num,
+        __Marshaller_math_with_protoc_options_Num);
+
+    /// <summary>Service descriptor</summary>
+    public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+    {
+      get { return global::MathWithProtocOptions.MathWithProtocOptionsReflection.Descriptor.Services[0]; }
+    }
+
+    /// <summary>Lite client for Math</summary>
+    public partial class MathClient : grpc::LiteClientBase
+    {
+      /// <summary>Creates a new client for Math that uses a custom <c>CallInvoker</c>.</summary>
+      /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
+      public MathClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+      {
+      }
+      /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+      protected MathClient() : base()
+      {
+      }
+
+      /// <summary>
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
+      /// </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::MathWithProtocOptions.DivReply Div(global::MathWithProtocOptions.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return Div(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
+      /// </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::MathWithProtocOptions.DivReply Div(global::MathWithProtocOptions.DivArgs request, grpc::CallOptions options)
+      {
+        return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
+      }
+      /// <summary>
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
+      /// </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::MathWithProtocOptions.DivReply> DivAsync(global::MathWithProtocOptions.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return DivAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
+      /// </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::MathWithProtocOptions.DivReply> DivAsync(global::MathWithProtocOptions.DivArgs request, grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
+      }
+      /// <summary>
+      /// DivMany accepts an arbitrary number of division args from the client stream
+      /// and sends back the results in the reply stream.  The stream continues until
+      /// the client closes its end; the server does the same after sending all the
+      /// replies.  The stream ends immediately if either end aborts.
+      /// </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::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply> DivMany(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return DivMany(new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      /// DivMany accepts an arbitrary number of division args from the client stream
+      /// and sends back the results in the reply stream.  The stream continues until
+      /// the client closes its end; the server does the same after sending all the
+      /// replies.  The stream ends immediately if either end aborts.
+      /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
+      public virtual grpc::AsyncDuplexStreamingCall<global::MathWithProtocOptions.DivArgs, global::MathWithProtocOptions.DivReply> DivMany(grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
+      }
+      /// <summary>
+      /// Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+      /// generates up to limit numbers; otherwise it continues until the call is
+      /// canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </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::MathWithProtocOptions.Num> Fib(global::MathWithProtocOptions.FibArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return Fib(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      /// Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+      /// generates up to limit numbers; otherwise it continues until the call is
+      /// canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </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::MathWithProtocOptions.Num> Fib(global::MathWithProtocOptions.FibArgs request, grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
+      }
+      /// <summary>
+      /// Sum sums a stream of numbers, returning the final result once the stream
+      /// is closed.
+      /// </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::MathWithProtocOptions.Num, global::MathWithProtocOptions.Num> Sum(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return Sum(new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      /// Sum sums a stream of numbers, returning the final result once the stream
+      /// is closed.
+      /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
+      public virtual grpc::AsyncClientStreamingCall<global::MathWithProtocOptions.Num, global::MathWithProtocOptions.Num> Sum(grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
+      }
+    }
+
+  }
+}
+#endregion
diff --git a/src/csharp/Grpc.Examples/math_with_protoc_options.proto b/src/csharp/Grpc.Examples/math_with_protoc_options.proto
new file mode 100644 (file)
index 0000000..ca13c6d
--- /dev/null
@@ -0,0 +1,65 @@
+
+// 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.
+
+syntax = "proto3";
+
+package math_with_protoc_options;
+
+message DivArgs {
+  int64 dividend = 1;
+  int64 divisor = 2;
+}
+
+message DivReply {
+  int64 quotient = 1;
+  int64 remainder = 2;
+}
+
+message FibArgs {
+  int64 limit = 1;
+}
+
+message Num {
+  int64 num = 1;
+}
+
+message FibReply {
+  int64 count = 1;
+}
+
+service Math {
+  // Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+  // and remainder.
+  rpc Div (DivArgs) returns (DivReply) {
+  }
+
+  // DivMany accepts an arbitrary number of division args from the client stream
+  // and sends back the results in the reply stream.  The stream continues until
+  // the client closes its end; the server does the same after sending all the
+  // replies.  The stream ends immediately if either end aborts.
+  rpc DivMany (stream DivArgs) returns (stream DivReply) {
+  }
+
+  // Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+  // generates up to limit numbers; otherwise it continues until the call is
+  // canceled.  Unlike Fib above, Fib has no final FibReply.
+  rpc Fib (FibArgs) returns (stream Num) {
+  }
+
+  // Sum sums a stream of numbers, returning the final result once the stream
+  // is closed.
+  rpc Sum (stream Num) returns (Num) {
+  }
+}
index e5af4a9..bbba68e 100644 (file)
@@ -28,7 +28,7 @@ namespace Grpc.Testing {
             "DGdycGMudGVzdGluZyIyCglEZWJ1Z0luZm8SFQoNc3RhY2tfZW50cmllcxgB",
             "IAMoCRIOCgZkZXRhaWwYAiABKAkiUAoLRXJyb3JTdGF0dXMSDAoEY29kZRgB",
             "IAEoBRIVCg1lcnJvcl9tZXNzYWdlGAIgASgJEhwKFGJpbmFyeV9lcnJvcl9k",
-            "ZXRhaWxzGAMgASgJIv8DCg1SZXF1ZXN0UGFyYW1zEhUKDWVjaG9fZGVhZGxp",
+            "ZXRhaWxzGAMgASgJIqAECg1SZXF1ZXN0UGFyYW1zEhUKDWVjaG9fZGVhZGxp",
             "bmUYASABKAgSHgoWY2xpZW50X2NhbmNlbF9hZnRlcl91cxgCIAEoBRIeChZz",
             "ZXJ2ZXJfY2FuY2VsX2FmdGVyX3VzGAMgASgFEhUKDWVjaG9fbWV0YWRhdGEY",
             "BCABKAgSGgoSY2hlY2tfYXV0aF9jb250ZXh0GAUgASgIEh8KF3Jlc3BvbnNl",
@@ -39,18 +39,19 @@ namespace Grpc.Testing {
             "Zy5EZWJ1Z0luZm8SEgoKc2VydmVyX2RpZRgMIAEoCBIcChRiaW5hcnlfZXJy",
             "b3JfZGV0YWlscxgNIAEoCRIxCg5leHBlY3RlZF9lcnJvchgOIAEoCzIZLmdy",
             "cGMudGVzdGluZy5FcnJvclN0YXR1cxIXCg9zZXJ2ZXJfc2xlZXBfdXMYDyAB",
-            "KAUSGwoTYmFja2VuZF9jaGFubmVsX2lkeBgQIAEoBSJKCgtFY2hvUmVxdWVz",
-            "dBIPCgdtZXNzYWdlGAEgASgJEioKBXBhcmFtGAIgASgLMhsuZ3JwYy50ZXN0",
-            "aW5nLlJlcXVlc3RQYXJhbXMiRgoOUmVzcG9uc2VQYXJhbXMSGAoQcmVxdWVz",
-            "dF9kZWFkbGluZRgBIAEoAxIMCgRob3N0GAIgASgJEgwKBHBlZXIYAyABKAki",
-            "TAoMRWNob1Jlc3BvbnNlEg8KB21lc3NhZ2UYASABKAkSKwoFcGFyYW0YAiAB",
-            "KAsyHC5ncnBjLnRlc3RpbmcuUmVzcG9uc2VQYXJhbXNiBnByb3RvMw=="));
+            "KAUSGwoTYmFja2VuZF9jaGFubmVsX2lkeBgQIAEoBRIfChdlY2hvX21ldGFk",
+            "YXRhX2luaXRpYWxseRgRIAEoCCJKCgtFY2hvUmVxdWVzdBIPCgdtZXNzYWdl",
+            "GAEgASgJEioKBXBhcmFtGAIgASgLMhsuZ3JwYy50ZXN0aW5nLlJlcXVlc3RQ",
+            "YXJhbXMiRgoOUmVzcG9uc2VQYXJhbXMSGAoQcmVxdWVzdF9kZWFkbGluZRgB",
+            "IAEoAxIMCgRob3N0GAIgASgJEgwKBHBlZXIYAyABKAkiTAoMRWNob1Jlc3Bv",
+            "bnNlEg8KB21lc3NhZ2UYASABKAkSKwoFcGFyYW0YAiABKAsyHC5ncnBjLnRl",
+            "c3RpbmcuUmVzcG9uc2VQYXJhbXNCA/gBAWIGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.DebugInfo), global::Grpc.Testing.DebugInfo.Parser, new[]{ "StackEntries", "Detail" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ErrorStatus), global::Grpc.Testing.ErrorStatus.Parser, new[]{ "Code", "ErrorMessage", "BinaryErrorDetails" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.RequestParams), global::Grpc.Testing.RequestParams.Parser, new[]{ "EchoDeadline", "ClientCancelAfterUs", "ServerCancelAfterUs", "EchoMetadata", "CheckAuthContext", "ResponseMessageLength", "EchoPeer", "ExpectedClientIdentity", "SkipCancelledCheck", "ExpectedTransportSecurityType", "DebugInfo", "ServerDie", "BinaryErrorDetails", "ExpectedError", "ServerSleepUs", "BackendChannelIdx" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.RequestParams), global::Grpc.Testing.RequestParams.Parser, new[]{ "EchoDeadline", "ClientCancelAfterUs", "ServerCancelAfterUs", "EchoMetadata", "CheckAuthContext", "ResponseMessageLength", "EchoPeer", "ExpectedClientIdentity", "SkipCancelledCheck", "ExpectedTransportSecurityType", "DebugInfo", "ServerDie", "BinaryErrorDetails", "ExpectedError", "ServerSleepUs", "BackendChannelIdx", "EchoMetadataInitially" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EchoRequest), global::Grpc.Testing.EchoRequest.Parser, new[]{ "Message", "Param" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParams), global::Grpc.Testing.ResponseParams.Parser, new[]{ "RequestDeadline", "Host", "Peer" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EchoResponse), global::Grpc.Testing.EchoResponse.Parser, new[]{ "Message", "Param" }, null, null, null)
@@ -441,6 +442,7 @@ namespace Grpc.Testing {
       expectedError_ = other.expectedError_ != null ? other.expectedError_.Clone() : null;
       serverSleepUs_ = other.serverSleepUs_;
       backendChannelIdx_ = other.backendChannelIdx_;
+      echoMetadataInitially_ = other.echoMetadataInitially_;
       _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
     }
 
@@ -637,6 +639,17 @@ namespace Grpc.Testing {
       }
     }
 
+    /// <summary>Field number for the "echo_metadata_initially" field.</summary>
+    public const int EchoMetadataInitiallyFieldNumber = 17;
+    private bool echoMetadataInitially_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool EchoMetadataInitially {
+      get { return echoMetadataInitially_; }
+      set {
+        echoMetadataInitially_ = value;
+      }
+    }
+
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public override bool Equals(object other) {
       return Equals(other as RequestParams);
@@ -666,6 +679,7 @@ namespace Grpc.Testing {
       if (!object.Equals(ExpectedError, other.ExpectedError)) return false;
       if (ServerSleepUs != other.ServerSleepUs) return false;
       if (BackendChannelIdx != other.BackendChannelIdx) return false;
+      if (EchoMetadataInitially != other.EchoMetadataInitially) return false;
       return Equals(_unknownFields, other._unknownFields);
     }
 
@@ -688,6 +702,7 @@ namespace Grpc.Testing {
       if (expectedError_ != null) hash ^= ExpectedError.GetHashCode();
       if (ServerSleepUs != 0) hash ^= ServerSleepUs.GetHashCode();
       if (BackendChannelIdx != 0) hash ^= BackendChannelIdx.GetHashCode();
+      if (EchoMetadataInitially != false) hash ^= EchoMetadataInitially.GetHashCode();
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
       }
@@ -765,6 +780,10 @@ namespace Grpc.Testing {
         output.WriteRawTag(128, 1);
         output.WriteInt32(BackendChannelIdx);
       }
+      if (EchoMetadataInitially != false) {
+        output.WriteRawTag(136, 1);
+        output.WriteBool(EchoMetadataInitially);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -821,6 +840,9 @@ namespace Grpc.Testing {
       if (BackendChannelIdx != 0) {
         size += 2 + pb::CodedOutputStream.ComputeInt32Size(BackendChannelIdx);
       }
+      if (EchoMetadataInitially != false) {
+        size += 2 + 1;
+      }
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
       }
@@ -886,6 +908,9 @@ namespace Grpc.Testing {
       if (other.BackendChannelIdx != 0) {
         BackendChannelIdx = other.BackendChannelIdx;
       }
+      if (other.EchoMetadataInitially != false) {
+        EchoMetadataInitially = other.EchoMetadataInitially;
+      }
       _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
     }
 
@@ -967,6 +992,10 @@ namespace Grpc.Testing {
             BackendChannelIdx = input.ReadInt32();
             break;
           }
+          case 136: {
+            EchoMetadataInitially = input.ReadBool();
+            break;
+          }
         }
       }
     }
index 4750353..83b0095 100644 (file)
@@ -185,6 +185,9 @@ namespace Grpc.IntegrationTesting
                 case "unimplemented_service":
                     RunUnimplementedService(new UnimplementedService.UnimplementedServiceClient(channel));
                     break;
+                case "special_status_message":
+                    await RunSpecialStatusMessageAsync(client);
+                    break;
                 case "unimplemented_method":
                     RunUnimplementedMethod(client);
                     break;
@@ -567,6 +570,33 @@ namespace Grpc.IntegrationTesting
             Console.WriteLine("Passed!");
         }
 
+        private static async Task RunSpecialStatusMessageAsync(TestService.TestServiceClient client)
+        {
+            Console.WriteLine("running special_status_message");
+
+            var echoStatus = new EchoStatus
+            {
+                Code = 2,
+                Message = "\t\ntest with whitespace\r\nand Unicode BMP â˜º and non-BMP ðŸ˜ˆ\t\n"
+            };
+
+            try
+            {
+                await client.UnaryCallAsync(new SimpleRequest
+                {
+                    ResponseStatus = echoStatus
+                });
+                Assert.Fail();
+            }
+            catch (RpcException e)
+            {
+                Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+                Assert.AreEqual(echoStatus.Message, e.Status.Detail);
+            }
+
+            Console.WriteLine("Passed!");
+        }
+
         public static void RunUnimplementedService(UnimplementedService.UnimplementedServiceClient client)
         {
             Console.WriteLine("running unimplemented_service");
index 40cfbeb..36a0ea3 100644 (file)
@@ -136,7 +136,7 @@ namespace Grpc.Tools
             new ErrorListFilter
             {
                 Pattern = new Regex(
-                    pattern: "(?'FILENAME'.+)\\((?'LINE'\\d+)\\) ?: ?warning in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)",
+                    pattern: "^(?'FILENAME'.+?)\\((?'LINE'\\d+)\\) ?: ?warning in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)",
                     options: RegexOptions.Compiled | RegexOptions.IgnoreCase,
                     matchTimeout: s_regexTimeout),
                 LogAction = (log, match) =>
@@ -162,7 +162,7 @@ namespace Grpc.Tools
             new ErrorListFilter
             {
                 Pattern = new Regex(
-                    pattern: "(?'FILENAME'.+)\\((?'LINE'\\d+)\\) ?: ?error in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)",
+                    pattern: "^(?'FILENAME'.+?)\\((?'LINE'\\d+)\\) ?: ?error in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)",
                     options: RegexOptions.Compiled | RegexOptions.IgnoreCase,
                     matchTimeout: s_regexTimeout),
                 LogAction = (log, match) =>
@@ -185,10 +185,10 @@ namespace Grpc.Tools
 
             // Example warning without location
             //../Protos/greet.proto: warning: Import google/protobuf/empty.proto but not used.
-            new ErrorListFilter 
+            new ErrorListFilter
             {
                 Pattern = new Regex(
-                    pattern: "(?'FILENAME'.+): ?warning: ?(?'TEXT'.*)",
+                    pattern: "^(?'FILENAME'.+?): ?warning: ?(?'TEXT'.*)",
                     options: RegexOptions.Compiled | RegexOptions.IgnoreCase,
                     matchTimeout: s_regexTimeout),
                 LogAction = (log, match) =>
@@ -211,7 +211,7 @@ namespace Grpc.Tools
             new ErrorListFilter
             {
                 Pattern = new Regex(
-                    pattern: "(?'FILENAME'.+): ?(?'TEXT'.*)",
+                    pattern: "^(?'FILENAME'.+?): ?(?'TEXT'.*)",
                     options: RegexOptions.Compiled | RegexOptions.IgnoreCase,
                     matchTimeout: s_regexTimeout),
                 LogAction = (log, match) =>
@@ -518,7 +518,7 @@ namespace Grpc.Tools
             foreach (ErrorListFilter filter in s_errorListFilters)
             {
                 Match match = filter.Pattern.Match(singleLine);
-                
+
                 if (match.Success)
                 {
                     filter.LogAction(Log, match);
index 6686258..2728c8b 100644 (file)
       </EnumProperty.DataSource>
     </EnumProperty>
 
+    <EnumProperty Name="ClientBaseType" DisplayName="gRPC Client Base Type"
+                  Category="gRPC" Default="ClientBase"
+                  Description="The base type to use for the client. This is an experimental feature.">
+      <EnumValue Name="ClientBase" DisplayName="Use ClientBase" />
+      <EnumValue Name="LiteClientBase" DisplayName="Use LiteClientBase" />
+      <EnumProperty.DataSource>
+        <DataSource ItemType="Protobuf" SourceOfDefaultValue="AfterContext"
+                    PersistenceStyle="Attribute" />
+      </EnumProperty.DataSource>
+    </EnumProperty>
+
   </Rule>
 </ProjectSchemaDefinitions>
index dd01b81..bc78e34 100644 (file)
@@ -42,6 +42,9 @@
       <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Server' ">
         <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_client</_GrpcOutputOptions>
       </Protobuf_Compile>
+      <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Client' or  '%(Protobuf_Compile.GrpcServices)' == 'Both' ">
+        <_GrpcOutputOptions Condition=" '%(Protobuf_Compile.ClientBaseType)' == 'LiteClientBase' ">%(Protobuf_Compile._GrpcOutputOptions);lite_client</_GrpcOutputOptions>
+      </Protobuf_Compile>
     </ItemGroup>
   </Target>
 </Project>
index c01cae0..13c8502 100644 (file)
@@ -17,20 +17,20 @@ PREREQUISITES
 When using gRPC C# under .NET Core you only need to [install .NET Core](https://www.microsoft.com/net/core).
 
 In addition to that, you can also use gRPC C# with these runtimes / IDEs
-- Windows: .NET Framework 4.5+, Visual Studio 2013, 2015, 2017, Visual Studio Code
-- Linux: Mono 4+, Visual Studio Code, MonoDevelop 5.9+ 
-- Mac OS X: Mono 4+, Visual Studio Code, Xamarin Studio 5.9+
+- Windows: .NET Framework 4.5+, Visual Studio 2013 or newer, Visual Studio Code
+- Linux: Mono 4+, Visual Studio Code
+- Mac OS X: Mono 4+, Visual Studio Code, Visual Studio for Mac
 
 HOW TO USE
 --------------
 
 **Windows, Linux, Mac OS X**
 
-- Open Visual Studio / MonoDevelop / Xamarin Studio and start a new project/solution (alternatively, you can create a new project from command line with `dotnet` SDK)
+- Open Visual Studio and start a new project/solution (alternatively, you can create a new project from command line with `dotnet` SDK)
 
 - Add the [Grpc](https://www.nuget.org/packages/Grpc/) NuGet package as a dependency (Project options -> Manage NuGet Packages). 
 
-- To be able to generate code from Protocol Buffer (`.proto`) file definitions, add the [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) NuGet package that contains Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin.
+- To be able to generate code from Protocol Buffer (`.proto`) file definitions, add the [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) NuGet package which provides [code generation integrated into your build](BUILD-INTEGRATION.md).
 
 **Xamarin.Android and Xamarin.iOS (Experimental only)**
 
index 949b683..62b8685 100644 (file)
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>1.21.3</GrpcCsharpVersion>
+    <GrpcCsharpVersion>1.22.0</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.7.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
index a371568..8c58c2f 100644 (file)
@@ -13,7 +13,7 @@
 @rem limitations under the License.
 
 @rem Current package versions
-set VERSION=1.21.3
+set VERSION=1.22.0
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
similarity index 90%
rename from src/csharp/doc/generate_reference_docs.sh
rename to src/csharp/docfx/generate_reference_docs.sh
index c20d6c3..dbed2ba 100755 (executable)
@@ -23,7 +23,7 @@ rm -rf html obj grpc-gh-pages
 # generate into src/csharp/doc/html directory
 cd ..
 docker run --rm -v "$(pwd)":/work -w /work/doc --user "$(id -u):$(id -g)" -it tsgkadot/docker-docfx:latest docfx
-cd doc
+cd docfx
 
 # prepare a clone of "gh-pages" branch where the generated docs are stored
 GITHUB_USER="${USER}"
@@ -35,4 +35,4 @@ git remote add origin "git@github.com:${GITHUB_USER}/grpc.git"
 rm -r csharp
 cp -r ../html csharp
 
-echo "Done. Go to src/csharp/doc/grpc-gh-pages git repository and create a pull request to update the generated docs."
+echo "Done. Go to src/csharp/docfx/grpc-gh-pages git repository and create a pull request to update the generated docs."
index e79728f..81463ac 100755 (executable)
@@ -26,6 +26,8 @@ TESTING_DIR=src/csharp/Grpc.IntegrationTesting
 
 $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
     -I src/proto src/proto/math/math.proto
+$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR --grpc_opt=lite_client,no_server \
+    -I src/csharp/Grpc.Examples src/csharp/Grpc.Examples/math_with_protoc_options.proto
 
 $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
     -I src/proto src/proto/grpc/health/v1/health.proto
index c4b5888..c4e9c23 100644 (file)
@@ -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.21.3'
+  v = '1.22.0'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
@@ -101,7 +101,7 @@ Pod::Spec.new do |s|
   s.preserve_paths = plugin
 
   # Restrict the protoc version to the one supported by this plugin.
-  s.dependency '!ProtoCompiler', '3.7.0'
+  s.dependency '!ProtoCompiler', '3.8.0'
   # For the Protobuf dependency not to complain:
   s.ios.deployment_target = '7.0'
   s.osx.deployment_target = '10.9'
index 58d74be..d8ce4d8 100644 (file)
@@ -36,7 +36,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'
-  v = '3.7.0'
+  v = '3.8.0'
   s.version  = v
   s.summary  = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files'
   s.description = <<-DESC
index a430d5c..d02ec60 100644 (file)
@@ -170,12 +170,24 @@ extern NSString *const kGRPCTrailersKey;
 - (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata;
 
 /**
+ * This method is deprecated and does not work with interceptors. To use GRPCCall2 interface with
+ * interceptor, implement didReceiveData: instead. To implement an interceptor, please leave this
+ * method unimplemented and implement didReceiveData: method instead. If this method and
+ * didReceiveRawMessage are implemented at the same time, implementation of this method will be
+ * ignored.
+ *
  * Issued when a message is received from the server. The message is the raw data received from the
  * server, with decompression and without proto deserialization.
  */
 - (void)didReceiveRawMessage:(nullable NSData *)message;
 
 /**
+ * Issued when a decompressed message is received from the server. The message is decompressed, and
+ * deserialized if a marshaller is provided to the call (marshaller is work in progress).
+ */
+- (void)didReceiveData:(id)data;
+
+/**
  * Issued when a call finished. If the call finished successfully, \a error is nil and \a
  * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error
  * is non-nil and contains the corresponding error information, including gRPC error codes and
@@ -260,9 +272,10 @@ extern NSString *const kGRPCTrailersKey;
 - (void)cancel;
 
 /**
- * Send a message to the server. Data are sent as raw bytes in gRPC message frames.
+ * Send a message to the server. The data is subject to marshaller serialization and compression
+ * (marshaller is work in progress).
  */
-- (void)writeData:(NSData *)data;
+- (void)writeData:(id)data;
 
 /**
  * Finish the RPC request and half-close the call. The server may still send messages and/or
index 495f942..e97ed6e 100644 (file)
@@ -17,8 +17,9 @@
  */
 
 #import "GRPCCall.h"
-
 #import "GRPCCall+OAuth2.h"
+#import "GRPCCallOptions.h"
+#import "GRPCInterceptor.h"
 
 #import <RxLibrary/GRXBufferedPipe.h>
 #import <RxLibrary/GRXConcurrentWriteable.h>
@@ -27,7 +28,8 @@
 #include <grpc/grpc.h>
 #include <grpc/support/time.h>
 
-#import "GRPCCallOptions.h"
+#import "private/GRPCCall+V2API.h"
+#import "private/GRPCCallInternal.h"
 #import "private/GRPCChannelPool.h"
 #import "private/GRPCCompletionQueue.h"
 #import "private/GRPCConnectivityMonitor.h"
@@ -57,11 +59,7 @@ const char *kCFStreamVarName = "grpc_cfstream";
 @property(atomic, strong) NSDictionary *responseHeaders;
 @property(atomic, strong) NSDictionary *responseTrailers;
 
-- (instancetype)initWithHost:(NSString *)host
-                        path:(NSString *)path
-                  callSafety:(GRPCCallSafety)safety
-              requestsWriter:(GRXWriter *)requestsWriter
-                 callOptions:(GRPCCallOptions *)callOptions;
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
 
 - (instancetype)initWithHost:(NSString *)host
                         path:(NSString *)path
@@ -70,8 +68,6 @@ const char *kCFStreamVarName = "grpc_cfstream";
                  callOptions:(GRPCCallOptions *)callOptions
                    writeDone:(void (^)(void))writeDone;
 
-- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
-
 @end
 
 @implementation GRPCRequestOptions
@@ -98,32 +94,23 @@ const char *kCFStreamVarName = "grpc_cfstream";
 
 @end
 
+/**
+ * This class acts as a wrapper for interceptors
+ */
 @implementation GRPCCall2 {
-  /** Options for the call. */
-  GRPCCallOptions *_callOptions;
   /** The handler of responses. */
-  id<GRPCResponseHandler> _handler;
+  id<GRPCResponseHandler> _responseHandler;
 
-  // Thread safety of ivars below are protected by _dispatchQueue.
+  /**
+   * Points to the first interceptor in the interceptor chain.
+   */
+  id<GRPCInterceptorInterface> _firstInterceptor;
 
   /**
-   * Make use of legacy GRPCCall to make calls. Nullified when call is finished.
+   * The actual call options being used by this call. It is different from the user-provided
+   * call options when the user provided a NULL call options object.
    */
-  GRPCCall *_call;
-  /** Flags whether initial metadata has been published to response handler. */
-  BOOL _initialMetadataPublished;
-  /** Streaming call writeable to the underlying call. */
-  GRXBufferedPipe *_pipe;
-  /** Serial dispatch queue for tasks inside the call. */
-  dispatch_queue_t _dispatchQueue;
-  /** Flags whether call has started. */
-  BOOL _started;
-  /** Flags whether call has been canceled. */
-  BOOL _canceled;
-  /** Flags whether call has been finished. */
-  BOOL _finished;
-  /** The number of pending messages receiving requests. */
-  NSUInteger _pendingReceiveNextMessages;
+  GRPCCallOptions *_actualCallOptions;
 }
 
 - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions
@@ -145,30 +132,43 @@ const char *kCFStreamVarName = "grpc_cfstream";
 
   if ((self = [super init])) {
     _requestOptions = [requestOptions copy];
-    if (callOptions == nil) {
-      _callOptions = [[GRPCCallOptions alloc] init];
+    _callOptions = [callOptions copy];
+    if (!_callOptions) {
+      _actualCallOptions = [[GRPCCallOptions alloc] init];
     } else {
-      _callOptions = [callOptions copy];
+      _actualCallOptions = [callOptions copy];
     }
-    _handler = responseHandler;
-    _initialMetadataPublished = NO;
-    _pipe = [GRXBufferedPipe pipe];
-    // Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
-    if (@available(iOS 8.0, macOS 10.10, *)) {
-      _dispatchQueue = dispatch_queue_create(
-          NULL,
-          dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
+    _responseHandler = responseHandler;
+
+    // Initialize the interceptor chain
+    GRPCCall2Internal *internalCall = [[GRPCCall2Internal alloc] init];
+    id<GRPCInterceptorInterface> nextInterceptor = internalCall;
+    GRPCInterceptorManager *nextManager = nil;
+    NSArray *interceptorFactories = _actualCallOptions.interceptorFactories;
+    if (interceptorFactories.count == 0) {
+      [internalCall setResponseHandler:_responseHandler];
     } else {
-#else
-    {
-#endif
-      _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+      for (int i = (int)interceptorFactories.count - 1; i >= 0; i--) {
+        GRPCInterceptorManager *manager =
+            [[GRPCInterceptorManager alloc] initWithNextInterceptor:nextInterceptor];
+        GRPCInterceptor *interceptor =
+            [interceptorFactories[i] createInterceptorWithManager:manager];
+        NSAssert(interceptor != nil, @"Failed to create interceptor");
+        if (interceptor == nil) {
+          return nil;
+        }
+        if (i == (int)interceptorFactories.count - 1) {
+          [internalCall setResponseHandler:interceptor];
+        } else {
+          [nextManager setPreviousInterceptor:interceptor];
+        }
+        nextInterceptor = interceptor;
+        nextManager = manager;
+      }
+
+      [nextManager setPreviousInterceptor:_responseHandler];
     }
-    dispatch_set_target_queue(_dispatchQueue, responseHandler.dispatchQueue);
-    _started = NO;
-    _canceled = NO;
-    _finished = NO;
+    _firstInterceptor = nextInterceptor;
   }
 
   return self;
@@ -181,236 +181,65 @@ const char *kCFStreamVarName = "grpc_cfstream";
 }
 
 - (void)start {
-  GRPCCall *copiedCall = nil;
+  id<GRPCInterceptorInterface> copiedFirstInterceptor;
   @synchronized(self) {
-    NSAssert(!_started, @"Call already started.");
-    NSAssert(!_canceled, @"Call already canceled.");
-    if (_started) {
-      return;
-    }
-    if (_canceled) {
-      return;
-    }
-
-    _started = YES;
-    if (!_callOptions) {
-      _callOptions = [[GRPCCallOptions alloc] init];
-    }
-
-    _call = [[GRPCCall alloc] initWithHost:_requestOptions.host
-                                      path:_requestOptions.path
-                                callSafety:_requestOptions.safety
-                            requestsWriter:_pipe
-                               callOptions:_callOptions
-                                 writeDone:^{
-                                   @synchronized(self) {
-                                     if (self->_handler) {
-                                       [self issueDidWriteData];
-                                     }
-                                   }
-                                 }];
-    [_call setResponseDispatchQueue:_dispatchQueue];
-    if (_callOptions.initialMetadata) {
-      [_call.requestHeaders addEntriesFromDictionary:_callOptions.initialMetadata];
-    }
-    if (_pendingReceiveNextMessages > 0) {
-      [_call receiveNextMessages:_pendingReceiveNextMessages];
-      _pendingReceiveNextMessages = 0;
-    }
-    copiedCall = _call;
+    copiedFirstInterceptor = _firstInterceptor;
   }
-
-  void (^valueHandler)(id value) = ^(id value) {
-    @synchronized(self) {
-      if (self->_handler) {
-        if (!self->_initialMetadataPublished) {
-          self->_initialMetadataPublished = YES;
-          [self issueInitialMetadata:self->_call.responseHeaders];
-        }
-        if (value) {
-          [self issueMessage:value];
-        }
-      }
-    }
-  };
-  void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) {
-    @synchronized(self) {
-      if (self->_handler) {
-        if (!self->_initialMetadataPublished) {
-          self->_initialMetadataPublished = YES;
-          [self issueInitialMetadata:self->_call.responseHeaders];
-        }
-        [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil];
-      }
-      // Clearing _call must happen *after* dispatching close in order to get trailing
-      // metadata from _call.
-      if (self->_call) {
-        // Clean up the request writers. This should have no effect to _call since its
-        // response writeable is already nullified.
-        [self->_pipe writesFinishedWithError:nil];
-        self->_call = nil;
-        self->_pipe = nil;
-      }
-    }
-  };
-  id<GRXWriteable> responseWriteable =
-      [[GRXWriteable alloc] initWithValueHandler:valueHandler completionHandler:completionHandler];
-  [copiedCall startWithWriteable:responseWriteable];
-}
-
-- (void)cancel {
-  GRPCCall *copiedCall = nil;
-  @synchronized(self) {
-    if (_canceled) {
-      return;
-    }
-
-    _canceled = YES;
-
-    copiedCall = _call;
-    _call = nil;
-    _pipe = nil;
-
-    if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
-      dispatch_async(_dispatchQueue, ^{
-        // Copy to local so that block is freed after cancellation completes.
-        id<GRPCResponseHandler> copiedHandler = nil;
-        @synchronized(self) {
-          copiedHandler = self->_handler;
-          self->_handler = nil;
-        }
-
-        [copiedHandler didCloseWithTrailingMetadata:nil
-                                              error:[NSError errorWithDomain:kGRPCErrorDomain
-                                                                        code:GRPCErrorCodeCancelled
-                                                                    userInfo:@{
-                                                                      NSLocalizedDescriptionKey :
-                                                                          @"Canceled by app"
-                                                                    }]];
-      });
-    } else {
-      _handler = nil;
-    }
+  GRPCRequestOptions *requestOptions = [_requestOptions copy];
+  GRPCCallOptions *callOptions = [_actualCallOptions copy];
+  if ([copiedFirstInterceptor respondsToSelector:@selector(startWithRequestOptions:callOptions:)]) {
+    dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
+      [copiedFirstInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
+    });
   }
-  [copiedCall cancel];
 }
 
-- (void)writeData:(NSData *)data {
-  GRXBufferedPipe *copiedPipe = nil;
+- (void)cancel {
+  id<GRPCInterceptorInterface> copiedFirstInterceptor;
   @synchronized(self) {
-    NSAssert(!_canceled, @"Call already canceled.");
-    NSAssert(!_finished, @"Call is half-closed before sending data.");
-    if (_canceled) {
-      return;
-    }
-    if (_finished) {
-      return;
-    }
-
-    if (_pipe) {
-      copiedPipe = _pipe;
-    }
+    copiedFirstInterceptor = _firstInterceptor;
   }
-  [copiedPipe writeValue:data];
-}
-
-- (void)finish {
-  GRXBufferedPipe *copiedPipe = nil;
-  @synchronized(self) {
-    NSAssert(_started, @"Call not started.");
-    NSAssert(!_canceled, @"Call already canceled.");
-    NSAssert(!_finished, @"Call already half-closed.");
-    if (!_started) {
-      return;
-    }
-    if (_canceled) {
-      return;
-    }
-    if (_finished) {
-      return;
-    }
-
-    if (_pipe) {
-      copiedPipe = _pipe;
-      _pipe = nil;
-    }
-    _finished = YES;
+  if ([copiedFirstInterceptor respondsToSelector:@selector(cancel)]) {
+    dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
+      [copiedFirstInterceptor cancel];
+    });
   }
-  [copiedPipe writesFinishedWithError:nil];
 }
 
-- (void)issueInitialMetadata:(NSDictionary *)initialMetadata {
+- (void)writeData:(id)data {
+  id<GRPCInterceptorInterface> copiedFirstInterceptor;
   @synchronized(self) {
-    if (initialMetadata != nil &&
-        [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
-      dispatch_async(_dispatchQueue, ^{
-        id<GRPCResponseHandler> copiedHandler = nil;
-        @synchronized(self) {
-          copiedHandler = self->_handler;
-        }
-        [copiedHandler didReceiveInitialMetadata:initialMetadata];
-      });
-    }
+    copiedFirstInterceptor = _firstInterceptor;
   }
-}
-
-- (void)issueMessage:(id)message {
-  @synchronized(self) {
-    if (message != nil && [_handler respondsToSelector:@selector(didReceiveRawMessage:)]) {
-      dispatch_async(_dispatchQueue, ^{
-        id<GRPCResponseHandler> copiedHandler = nil;
-        @synchronized(self) {
-          copiedHandler = self->_handler;
-        }
-        [copiedHandler didReceiveRawMessage:message];
-      });
-    }
+  if ([copiedFirstInterceptor respondsToSelector:@selector(writeData:)]) {
+    dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
+      [copiedFirstInterceptor writeData:data];
+    });
   }
 }
 
-- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+- (void)finish {
+  id<GRPCInterceptorInterface> copiedFirstInterceptor;
   @synchronized(self) {
-    if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
-      dispatch_async(_dispatchQueue, ^{
-        id<GRPCResponseHandler> copiedHandler = nil;
-        @synchronized(self) {
-          copiedHandler = self->_handler;
-          // Clean up _handler so that no more responses are reported to the handler.
-          self->_handler = nil;
-        }
-        [copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error];
-      });
-    } else {
-      _handler = nil;
-    }
+    copiedFirstInterceptor = _firstInterceptor;
   }
-}
-
-- (void)issueDidWriteData {
-  @synchronized(self) {
-    if (_callOptions.flowControlEnabled && [_handler respondsToSelector:@selector(didWriteData)]) {
-      dispatch_async(_dispatchQueue, ^{
-        id<GRPCResponseHandler> copiedHandler = nil;
-        @synchronized(self) {
-          copiedHandler = self->_handler;
-        };
-        [copiedHandler didWriteData];
-      });
-    }
+  if ([copiedFirstInterceptor respondsToSelector:@selector(finish)]) {
+    dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
+      [copiedFirstInterceptor finish];
+    });
   }
 }
 
 - (void)receiveNextMessages:(NSUInteger)numberOfMessages {
-  // branching based on _callOptions.flowControlEnabled is handled inside _call
-  GRPCCall *copiedCall = nil;
+  id<GRPCInterceptorInterface> copiedFirstInterceptor;
   @synchronized(self) {
-    copiedCall = _call;
-    if (copiedCall == nil) {
-      _pendingReceiveNextMessages += numberOfMessages;
-      return;
-    }
+    copiedFirstInterceptor = _firstInterceptor;
+  }
+  if ([copiedFirstInterceptor respondsToSelector:@selector(receiveNextMessages:)]) {
+    dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
+      [copiedFirstInterceptor receiveNextMessages:numberOfMessages];
+    });
   }
-  [copiedCall receiveNextMessages:numberOfMessages];
 }
 
 @end
@@ -648,6 +477,8 @@ const char *kCFStreamVarName = "grpc_cfstream";
 }
 
 - (void)dealloc {
+  [GRPCConnectivityMonitor unregisterObserver:self];
+
   __block GRPCWrappedCall *wrappedCall = _wrappedCall;
   dispatch_async(_callQueue, ^{
     wrappedCall = nil;
@@ -883,7 +714,12 @@ const char *kCFStreamVarName = "grpc_cfstream";
     __strong GRPCCall *strongSelf = weakSelf;
     if (strongSelf) {
       @synchronized(strongSelf) {
-        strongSelf.responseHeaders = headers;
+        // it is ok to set nil because headers are only received once
+        strongSelf.responseHeaders = nil;
+        // copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed
+        NSDictionary *copiedHeaders =
+            [[NSDictionary alloc] initWithDictionary:headers copyItems:YES];
+        strongSelf.responseHeaders = copiedHeaders;
         strongSelf->_pendingCoreRead = NO;
         [strongSelf maybeStartNextRead];
       }
index 9f77652..98511e3 100644 (file)
@@ -98,6 +98,14 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) {
  */
 @property(readonly) BOOL flowControlEnabled;
 
+/**
+ * An array of interceptor factories. When a call starts, interceptors are created
+ * by these factories and chained together with the same order as the factories in
+ * this array. This parameter should not be modified by any interceptor and will
+ * not take effect if done so.
+ */
+@property(copy, readonly) NSArray *interceptorFactories;
+
 // OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
 
 /**
@@ -253,6 +261,14 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) {
  */
 @property(readwrite) BOOL flowControlEnabled;
 
+/**
+ * An array of interceptor factories. When a call starts, interceptors are created
+ * by these factories and chained together with the same order as the factories in
+ * this array. This parameter should not be modified by any interceptor and will
+ * not take effect if done so.
+ */
+@property(copy, readwrite) NSArray *interceptorFactories;
+
 // OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
 
 /**
index e576641..392e42a 100644 (file)
@@ -23,6 +23,7 @@
 static NSString *const kDefaultServerAuthority = nil;
 static const NSTimeInterval kDefaultTimeout = 0;
 static const BOOL kDefaultFlowControlEnabled = NO;
+static NSArray *const kDefaultInterceptorFactories = nil;
 static NSDictionary *const kDefaultInitialMetadata = nil;
 static NSString *const kDefaultUserAgentPrefix = nil;
 static const NSUInteger kDefaultResponseSizeLimit = 0;
@@ -61,6 +62,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
   NSString *_serverAuthority;
   NSTimeInterval _timeout;
   BOOL _flowControlEnabled;
+  NSArray *_interceptorFactories;
   NSString *_oauth2AccessToken;
   id<GRPCAuthorizationProtocol> _authTokenProvider;
   NSDictionary *_initialMetadata;
@@ -87,6 +89,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
 @synthesize serverAuthority = _serverAuthority;
 @synthesize timeout = _timeout;
 @synthesize flowControlEnabled = _flowControlEnabled;
+@synthesize interceptorFactories = _interceptorFactories;
 @synthesize oauth2AccessToken = _oauth2AccessToken;
 @synthesize authTokenProvider = _authTokenProvider;
 @synthesize initialMetadata = _initialMetadata;
@@ -113,6 +116,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
   return [self initWithServerAuthority:kDefaultServerAuthority
                                timeout:kDefaultTimeout
                     flowControlEnabled:kDefaultFlowControlEnabled
+                  interceptorFactories:kDefaultInterceptorFactories
                      oauth2AccessToken:kDefaultOauth2AccessToken
                      authTokenProvider:kDefaultAuthTokenProvider
                        initialMetadata:kDefaultInitialMetadata
@@ -139,6 +143,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
 - (instancetype)initWithServerAuthority:(NSString *)serverAuthority
                                 timeout:(NSTimeInterval)timeout
                      flowControlEnabled:(BOOL)flowControlEnabled
+                   interceptorFactories:(NSArray *)interceptorFactories
                       oauth2AccessToken:(NSString *)oauth2AccessToken
                       authTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider
                         initialMetadata:(NSDictionary *)initialMetadata
@@ -164,6 +169,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
     _serverAuthority = [serverAuthority copy];
     _timeout = timeout < 0 ? 0 : timeout;
     _flowControlEnabled = flowControlEnabled;
+    _interceptorFactories = interceptorFactories;
     _oauth2AccessToken = [oauth2AccessToken copy];
     _authTokenProvider = authTokenProvider;
     _initialMetadata =
@@ -200,6 +206,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
       [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
                                                             timeout:_timeout
                                                  flowControlEnabled:_flowControlEnabled
+                                               interceptorFactories:_interceptorFactories
                                                   oauth2AccessToken:_oauth2AccessToken
                                                   authTokenProvider:_authTokenProvider
                                                     initialMetadata:_initialMetadata
@@ -229,6 +236,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
       initWithServerAuthority:[_serverAuthority copy]
                       timeout:_timeout
            flowControlEnabled:_flowControlEnabled
+         interceptorFactories:_interceptorFactories
             oauth2AccessToken:[_oauth2AccessToken copy]
             authTokenProvider:_authTokenProvider
               initialMetadata:[[NSDictionary alloc] initWithDictionary:_initialMetadata
@@ -310,6 +318,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
 @dynamic serverAuthority;
 @dynamic timeout;
 @dynamic flowControlEnabled;
+@dynamic interceptorFactories;
 @dynamic oauth2AccessToken;
 @dynamic authTokenProvider;
 @dynamic initialMetadata;
@@ -336,6 +345,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
   return [self initWithServerAuthority:kDefaultServerAuthority
                                timeout:kDefaultTimeout
                     flowControlEnabled:kDefaultFlowControlEnabled
+                  interceptorFactories:kDefaultInterceptorFactories
                      oauth2AccessToken:kDefaultOauth2AccessToken
                      authTokenProvider:kDefaultAuthTokenProvider
                        initialMetadata:kDefaultInitialMetadata
@@ -364,6 +374,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
       [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
                                                             timeout:_timeout
                                                  flowControlEnabled:_flowControlEnabled
+                                               interceptorFactories:_interceptorFactories
                                                   oauth2AccessToken:_oauth2AccessToken
                                                   authTokenProvider:_authTokenProvider
                                                     initialMetadata:_initialMetadata
@@ -393,6 +404,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
       initWithServerAuthority:_serverAuthority
                       timeout:_timeout
            flowControlEnabled:_flowControlEnabled
+         interceptorFactories:_interceptorFactories
             oauth2AccessToken:_oauth2AccessToken
             authTokenProvider:_authTokenProvider
               initialMetadata:_initialMetadata
@@ -433,6 +445,10 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
   _flowControlEnabled = flowControlEnabled;
 }
 
+- (void)setInterceptorFactories:(NSArray *)interceptorFactories {
+  _interceptorFactories = interceptorFactories;
+}
+
 - (void)setOauth2AccessToken:(NSString *)oauth2AccessToken {
   _oauth2AccessToken = [oauth2AccessToken copy];
 }
diff --git a/src/objective-c/GRPCClient/GRPCInterceptor.h b/src/objective-c/GRPCClient/GRPCInterceptor.h
new file mode 100644 (file)
index 0000000..3b62c1b
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *
+ * Copyright 2019 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.
+ *
+ */
+
+/**
+ * API for interceptors implementation. This feature is currently EXPERIMENTAL and is subject to
+ * breaking changes without prior notice.
+ *
+ * The interceptors in the gRPC system forms a chain. When a call is made by the user, each
+ * interceptor on the chain has chances to react to events of the call and make necessary
+ * modifications to the call's parameters, data, metadata, or flow.
+ *
+ *
+ *                                   -----------
+ *                                  | GRPCCall2 |
+ *                                   -----------
+ *                                        |
+ *                                        |
+ *                           --------------------------
+ *                          | GRPCInterceptorManager 1 |
+ *                           --------------------------
+ *                          | GRPCInterceptor 1        |
+ *                           --------------------------
+ *                                        |
+ *                                       ...
+ *                                        |
+ *                           --------------------------
+ *                          | GRPCInterceptorManager N |
+ *                           --------------------------
+ *                          | GRPCInterceptor N        |
+ *                           --------------------------
+ *                                        |
+ *                                        |
+ *                               ------------------
+ *                              | GRPCCallInternal |
+ *                               ------------------
+ *
+ * The chain of interceptors is initialized when the corresponding GRPCCall2 object or proto call
+ * object (GRPCUnaryProtoCall and GRPCStreamingProtoCall) is initialized. The initialization of the
+ * chain is controlled by the property interceptorFactories in the callOptions parameter of the
+ * corresponding call object. Property interceptorFactories is an array of
+ * id<GRPCInterceptorFactory> objects provided by the user. When a call object is initialized, each
+ * interceptor factory generates an interceptor object for the call. gRPC internally links the
+ * interceptors with each other and with the actual call object. The order of the interceptors in
+ * the chain is exactly the same as the order of factory objects in interceptorFactories property.
+ * All requests (start, write, finish, cancel, receive next) initiated by the user will be processed
+ * in the order of interceptors, and all responses (initial metadata, data, trailing metadata, write
+ * data done) are processed in the reverse order.
+ *
+ * Each interceptor in the interceptor chain should behave as a user of the next interceptor, and at
+ * the same time behave as a call to the previous interceptor. Therefore interceptor implementations
+ * must follow the state transition of gRPC calls and must also forward events that are consistent
+ * with the current state of the next/previous interceptor. They should also make sure that the
+ * events they forwarded to the next and previous interceptors will, in the end, make the neighbour
+ * interceptor terminate correctly and reaches "finished" state. The diagram below shows the state
+ * transitions. Any event not appearing on the diagram means the event is not permitted for that
+ * particular state.
+ *
+ *                                      writeData
+ *                                  receiveNextMessages
+ *                               didReceiveInitialMetadata
+ *                                    didReceiveData
+ *                                     didWriteData                   receiveNextmessages
+ *           writeData  -----             -----                 ----  didReceiveInitialMetadata
+ * receiveNextMessages |     |           |     |               |    | didReceiveData
+ *                     |     V           |     V               |    V didWriteData
+ *               -------------  start   ---------   finish    ------------
+ *              | initialized | -----> | started | --------> | half-close |
+ *               -------------          ---------             ------------
+ *                     |                     |                      |
+ *                     |                     | didClose             | didClose
+ *                     |cancel               | cancel               | cancel
+ *                     |                     V                      |
+ *                     |                 ----------                 |
+ *                      --------------> | finished | <--------------
+ *                                       ----------
+ *                                        |      ^ writeData
+ *                                        |      | finish
+ *                                         ------  cancel
+ *                                                 receiveNextMessages
+ *
+ * Events of requests and responses are dispatched to interceptor objects using the interceptor's
+ * dispatch queue. The dispatch queue should be serial queue to make sure the events are processed
+ * in order. Interceptor implementations must derive from GRPCInterceptor class. The class makes
+ * some basic implementation of all methods responding to an event of a call. If an interceptor does
+ * not care about a particular event, it can use the basic implementation of the GRPCInterceptor
+ * class, which simply forward the event to the next or previous interceptor in the chain.
+ *
+ * The interceptor object should be unique for each call since the call context is not passed to the
+ * interceptor object in a call event. However, the interceptors can be implemented to share states
+ * by receiving state sharing object from the factory upon construction.
+ */
+
+#import "GRPCCall.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class GRPCInterceptorManager;
+@class GRPCInterceptor;
+
+/**
+ * The GRPCInterceptorInterface defines the request events that can occur to an interceptr.
+ */
+@protocol GRPCInterceptorInterface<NSObject>
+
+/**
+ * The queue on which all methods of this interceptor should be dispatched on. The queue must be a
+ * serial queue.
+ */
+@property(readonly) dispatch_queue_t requestDispatchQueue;
+
+/**
+ * To start the call. This method will only be called once for each instance.
+ */
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions;
+
+/**
+ * To write data to the call.
+ */
+- (void)writeData:(id)data;
+
+/**
+ * To finish the stream of requests.
+ */
+- (void)finish;
+
+/**
+ * To cancel the call.
+ */
+- (void)cancel;
+
+/**
+ * To indicate the call that the previous interceptor is ready to receive more messages.
+ */
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
+
+@end
+
+/**
+ * An interceptor factory object should be used to create interceptor object for the call at the
+ * call start time.
+ */
+@protocol GRPCInterceptorFactory
+
+/**
+ * Create an interceptor object. gRPC uses the returned object as the interceptor for the current
+ * call
+ */
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
+
+@end
+
+/**
+ * The interceptor manager object retains reference to the next and previous interceptor object in
+ * the interceptor chain, and forward corresponding events to them. When a call terminates, it must
+ * invoke shutDown method of its corresponding manager so that references to other interceptors can
+ * be released.
+ */
+@interface GRPCInterceptorManager : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
++ (instancetype) new NS_UNAVAILABLE;
+
+- (nullable instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor
+    NS_DESIGNATED_INITIALIZER;
+
+/** Set the previous interceptor in the chain. Can only be set once. */
+- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor;
+
+/** Indicate shutdown of the interceptor; release the reference to other interceptors */
+- (void)shutDown;
+
+// Methods to forward GRPCInterceptorInterface calls to the next interceptor
+
+/** Notify the next interceptor in the chain to start the call and pass arguments */
+- (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions
+                            callOptions:(GRPCCallOptions *)callOptions;
+
+/** Pass a message to be sent to the next interceptor in the chain */
+- (void)writeNextInterceptorWithData:(id)data;
+
+/** Notify the next interceptor in the chain to finish the call */
+- (void)finishNextInterceptor;
+
+/** Notify the next interceptor in the chain to cancel the call */
+- (void)cancelNextInterceptor;
+
+/** Notify the next interceptor in the chain to receive more messages */
+- (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages;
+
+// Methods to forward GRPCResponseHandler callbacks to the previous object
+
+/** Forward initial metadata to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata;
+
+/** Forward a received message to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorWithData:(nullable id)data;
+
+/** Forward call close and trailing metadata to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:
+            (nullable NSDictionary *)trailingMetadata
+                                                      error:(nullable NSError *)error;
+
+/** Forward write completion to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorDidWriteData;
+
+@end
+
+/**
+ * Base class for a gRPC interceptor. The implementation of the base class provides default behavior
+ * of an interceptor, which is simply forward a request/callback to the next/previous interceptor in
+ * the chain. The base class implementation uses the same dispatch queue for both requests and
+ * callbacks.
+ *
+ * An interceptor implementation should inherit from this base class and initialize the base class
+ * with [super initWithInterceptorManager:dispatchQueue:] for the default implementation to function
+ * properly.
+ */
+@interface GRPCInterceptor : NSObject<GRPCInterceptorInterface, GRPCResponseHandler>
+
+- (instancetype)init NS_UNAVAILABLE;
+
++ (instancetype) new NS_UNAVAILABLE;
+
+/**
+ * Initialize the interceptor with the next interceptor in the chain, and provide the dispatch queue
+ * that this interceptor's methods are dispatched onto.
+ */
+- (nullable instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
+                               requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+                              responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
+    NS_DESIGNATED_INITIALIZER;
+
+// Default implementation of GRPCInterceptorInterface
+
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions;
+- (void)writeData:(id)data;
+- (void)finish;
+- (void)cancel;
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
+
+// Default implementation of GRPCResponeHandler
+
+- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata;
+- (void)didReceiveData:(id)data;
+- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
+                               error:(nullable NSError *)error;
+- (void)didWriteData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/GRPCInterceptor.m b/src/objective-c/GRPCClient/GRPCInterceptor.m
new file mode 100644 (file)
index 0000000..a385ecd
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *
+ * Copyright 2019 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 <Foundation/Foundation.h>
+
+#import "GRPCInterceptor.h"
+
+@implementation GRPCInterceptorManager {
+  id<GRPCInterceptorInterface> _nextInterceptor;
+  id<GRPCResponseHandler> _previousInterceptor;
+}
+
+- (instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor {
+  if ((self = [super init])) {
+    _nextInterceptor = nextInterceptor;
+  }
+
+  return self;
+}
+
+- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor {
+  _previousInterceptor = previousInterceptor;
+}
+
+- (void)shutDown {
+  _nextInterceptor = nil;
+  _previousInterceptor = nil;
+}
+
+- (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions
+                            callOptions:(GRPCCallOptions *)callOptions {
+  if (_nextInterceptor != nil) {
+    id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
+    dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
+      [copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
+    });
+  }
+}
+
+- (void)writeNextInterceptorWithData:(id)data {
+  if (_nextInterceptor != nil) {
+    id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
+    dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
+      [copiedNextInterceptor writeData:data];
+    });
+  }
+}
+
+- (void)finishNextInterceptor {
+  if (_nextInterceptor != nil) {
+    id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
+    dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
+      [copiedNextInterceptor finish];
+    });
+  }
+}
+
+- (void)cancelNextInterceptor {
+  if (_nextInterceptor != nil) {
+    id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
+    dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
+      [copiedNextInterceptor cancel];
+    });
+  }
+}
+
+/** Notify the next interceptor in the chain to receive more messages */
+- (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages {
+  if (_nextInterceptor != nil) {
+    id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
+    dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
+      [copiedNextInterceptor receiveNextMessages:numberOfMessages];
+    });
+  }
+}
+
+// Methods to forward GRPCResponseHandler callbacks to the previous object
+
+/** Forward initial metadata to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata {
+  if ([_previousInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
+    id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
+    dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
+      [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata];
+    });
+  }
+}
+
+/** Forward a received message to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorWithData:(id)data {
+  if ([_previousInterceptor respondsToSelector:@selector(didReceiveData:)]) {
+    id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
+    dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
+      [copiedPreviousInterceptor didReceiveData:data];
+    });
+  }
+}
+
+/** Forward call close and trailing metadata to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:
+            (nullable NSDictionary *)trailingMetadata
+                                                      error:(nullable NSError *)error {
+  if ([_previousInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
+    id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
+    dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
+      [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
+    });
+  }
+}
+
+/** Forward write completion to the previous interceptor in the chain */
+- (void)forwardPreviousInterceptorDidWriteData {
+  if ([_previousInterceptor respondsToSelector:@selector(didWriteData)]) {
+    id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
+    dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
+      [copiedPreviousInterceptor didWriteData];
+    });
+  }
+}
+
+@end
+
+@implementation GRPCInterceptor {
+  GRPCInterceptorManager *_manager;
+  dispatch_queue_t _requestDispatchQueue;
+  dispatch_queue_t _responseDispatchQueue;
+}
+
+- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
+                      requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+                     responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue {
+  if ((self = [super init])) {
+    _manager = interceptorManager;
+    _requestDispatchQueue = requestDispatchQueue;
+    _responseDispatchQueue = responseDispatchQueue;
+  }
+
+  return self;
+}
+
+- (dispatch_queue_t)requestDispatchQueue {
+  return _requestDispatchQueue;
+}
+
+- (dispatch_queue_t)dispatchQueue {
+  return _responseDispatchQueue;
+}
+
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions {
+  [_manager startNextInterceptorWithRequest:requestOptions callOptions:callOptions];
+}
+
+- (void)writeData:(id)data {
+  [_manager writeNextInterceptorWithData:data];
+}
+
+- (void)finish {
+  [_manager finishNextInterceptor];
+}
+
+- (void)cancel {
+  [_manager cancelNextInterceptor];
+  [_manager
+      forwardPreviousInterceptorCloseWithTrailingMetadata:nil
+                                                    error:[NSError
+                                                              errorWithDomain:kGRPCErrorDomain
+                                                                         code:GRPCErrorCodeCancelled
+                                                                     userInfo:@{
+                                                                       NSLocalizedDescriptionKey :
+                                                                           @"Canceled"
+                                                                     }]];
+  [_manager shutDown];
+}
+
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
+  [_manager receiveNextInterceptorMessages:numberOfMessages];
+}
+
+- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
+  [_manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
+}
+
+- (void)didReceiveRawMessage:(id)message {
+  NSAssert(NO,
+           @"The method didReceiveRawMessage is deprecated and cannot be used with interceptor");
+  NSLog(@"The method didReceiveRawMessage is deprecated and cannot be used with interceptor");
+  abort();
+}
+
+- (void)didReceiveData:(id)data {
+  [_manager forwardPreviousInterceptorWithData:data];
+}
+
+- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  [_manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata error:error];
+  [_manager shutDown];
+}
+
+- (void)didWriteData {
+  [_manager forwardPreviousInterceptorDidWriteData];
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCCall+V2API.h b/src/objective-c/GRPCClient/private/GRPCCall+V2API.h
new file mode 100644 (file)
index 0000000..22bf169
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2019 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.
+ *
+ */
+
+@interface GRPCCall (V2API)
+
+- (instancetype)initWithHost:(NSString *)host
+                        path:(NSString *)path
+                  callSafety:(GRPCCallSafety)safety
+              requestsWriter:(GRXWriter *)requestsWriter
+                 callOptions:(GRPCCallOptions *)callOptions;
+
+- (instancetype)initWithHost:(NSString *)host
+                        path:(NSString *)path
+                  callSafety:(GRPCCallSafety)safety
+              requestsWriter:(GRXWriter *)requestsWriter
+                 callOptions:(GRPCCallOptions *)callOptions
+                   writeDone:(void (^)(void))writeDone;
+
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCCallInternal.h b/src/objective-c/GRPCClient/private/GRPCCallInternal.h
new file mode 100644 (file)
index 0000000..ac2d1cb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2019 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 <GRPCClient/GRPCInterceptor.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GRPCCall2Internal : NSObject<GRPCInterceptorInterface>
+
+- (instancetype)init;
+
+- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler;
+
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(nullable GRPCCallOptions *)callOptions;
+
+- (void)writeData:(NSData *)data;
+
+- (void)finish;
+
+- (void)cancel;
+
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/GRPCCallInternal.m b/src/objective-c/GRPCClient/private/GRPCCallInternal.m
new file mode 100644 (file)
index 0000000..32e3815
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *
+ * Copyright 2019 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 "GRPCCallInternal.h"
+
+#import <GRPCClient/GRPCCall.h>
+#import <RxLibrary/GRXBufferedPipe.h>
+
+#import "GRPCCall+V2API.h"
+
+@implementation GRPCCall2Internal {
+  /** Request for the call. */
+  GRPCRequestOptions *_requestOptions;
+  /** Options for the call. */
+  GRPCCallOptions *_callOptions;
+  /** The handler of responses. */
+  id<GRPCResponseHandler> _handler;
+
+  /**
+   * Make use of legacy GRPCCall to make calls. Nullified when call is finished.
+   */
+  GRPCCall *_call;
+  /** Flags whether initial metadata has been published to response handler. */
+  BOOL _initialMetadataPublished;
+  /** Streaming call writeable to the underlying call. */
+  GRXBufferedPipe *_pipe;
+  /** Serial dispatch queue for tasks inside the call. */
+  dispatch_queue_t _dispatchQueue;
+  /** Flags whether call has started. */
+  BOOL _started;
+  /** Flags whether call has been canceled. */
+  BOOL _canceled;
+  /** Flags whether call has been finished. */
+  BOOL _finished;
+  /** The number of pending messages receiving requests. */
+  NSUInteger _pendingReceiveNextMessages;
+}
+
+- (instancetype)init {
+  if ((self = [super init])) {
+  // Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
+    if (@available(iOS 8.0, macOS 10.10, *)) {
+      _dispatchQueue = dispatch_queue_create(
+          NULL,
+          dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
+    } else {
+#else
+    {
+#endif
+      _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+    }
+    _pipe = [GRXBufferedPipe pipe];
+  }
+  return self;
+}
+
+- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler {
+  @synchronized(self) {
+    NSAssert(!_started, @"Call already started.");
+    if (_started) {
+      return;
+    }
+    _handler = responseHandler;
+    _initialMetadataPublished = NO;
+    _started = NO;
+    _canceled = NO;
+    _finished = NO;
+  }
+}
+
+- (dispatch_queue_t)requestDispatchQueue {
+  return _dispatchQueue;
+}
+
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions {
+  NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0,
+           @"Neither host nor path can be nil.");
+  NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value.");
+  if (requestOptions.host.length == 0 || requestOptions.path.length == 0) {
+    NSLog(@"Invalid host and path.");
+    return;
+  }
+  if (requestOptions.safety > GRPCCallSafetyCacheableRequest) {
+    NSLog(@"Invalid call safety.");
+    return;
+  }
+
+  @synchronized(self) {
+    NSAssert(_handler != nil, @"Response handler required.");
+    if (_handler == nil) {
+      NSLog(@"Invalid response handler.");
+      return;
+    }
+    _requestOptions = requestOptions;
+    if (callOptions == nil) {
+      _callOptions = [[GRPCCallOptions alloc] init];
+    } else {
+      _callOptions = [callOptions copy];
+    }
+  }
+
+  [self start];
+}
+
+- (void)start {
+  GRPCCall *copiedCall = nil;
+  @synchronized(self) {
+    NSAssert(!_started, @"Call already started.");
+    NSAssert(!_canceled, @"Call already canceled.");
+    if (_started) {
+      return;
+    }
+    if (_canceled) {
+      return;
+    }
+
+    _started = YES;
+
+    _call = [[GRPCCall alloc] initWithHost:_requestOptions.host
+                                      path:_requestOptions.path
+                                callSafety:_requestOptions.safety
+                            requestsWriter:_pipe
+                               callOptions:_callOptions
+                                 writeDone:^{
+                                   @synchronized(self) {
+                                     if (self->_handler) {
+                                       [self issueDidWriteData];
+                                     }
+                                   }
+                                 }];
+    [_call setResponseDispatchQueue:_dispatchQueue];
+    if (_callOptions.initialMetadata) {
+      [_call.requestHeaders addEntriesFromDictionary:_callOptions.initialMetadata];
+    }
+    if (_pendingReceiveNextMessages > 0) {
+      [_call receiveNextMessages:_pendingReceiveNextMessages];
+      _pendingReceiveNextMessages = 0;
+    }
+    copiedCall = _call;
+  }
+
+  void (^valueHandler)(id value) = ^(id value) {
+    @synchronized(self) {
+      if (self->_handler) {
+        if (!self->_initialMetadataPublished) {
+          self->_initialMetadataPublished = YES;
+          [self issueInitialMetadata:self->_call.responseHeaders];
+        }
+        if (value) {
+          [self issueMessage:value];
+        }
+      }
+    }
+  };
+  void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) {
+    @synchronized(self) {
+      if (self->_handler) {
+        if (!self->_initialMetadataPublished) {
+          self->_initialMetadataPublished = YES;
+          [self issueInitialMetadata:self->_call.responseHeaders];
+        }
+        [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil];
+      }
+      // Clearing _call must happen *after* dispatching close in order to get trailing
+      // metadata from _call.
+      if (self->_call) {
+        // Clean up the request writers. This should have no effect to _call since its
+        // response writeable is already nullified.
+        [self->_pipe writesFinishedWithError:nil];
+        self->_call = nil;
+        self->_pipe = nil;
+      }
+    }
+  };
+  id<GRXWriteable> responseWriteable =
+      [[GRXWriteable alloc] initWithValueHandler:valueHandler completionHandler:completionHandler];
+  [copiedCall startWithWriteable:responseWriteable];
+}
+
+- (void)cancel {
+  GRPCCall *copiedCall = nil;
+  @synchronized(self) {
+    if (_canceled) {
+      return;
+    }
+
+    _canceled = YES;
+
+    copiedCall = _call;
+    _call = nil;
+    _pipe = nil;
+
+    if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
+      id<GRPCResponseHandler> copiedHandler = _handler;
+      _handler = nil;
+      dispatch_async(copiedHandler.dispatchQueue, ^{
+        [copiedHandler didCloseWithTrailingMetadata:nil
+                                              error:[NSError errorWithDomain:kGRPCErrorDomain
+                                                                        code:GRPCErrorCodeCancelled
+                                                                    userInfo:@{
+                                                                      NSLocalizedDescriptionKey :
+                                                                          @"Canceled by app"
+                                                                    }]];
+      });
+    } else {
+      _handler = nil;
+    }
+  }
+  [copiedCall cancel];
+}
+
+- (void)writeData:(id)data {
+  GRXBufferedPipe *copiedPipe = nil;
+  @synchronized(self) {
+    NSAssert(!_canceled, @"Call already canceled.");
+    NSAssert(!_finished, @"Call is half-closed before sending data.");
+    if (_canceled) {
+      return;
+    }
+    if (_finished) {
+      return;
+    }
+
+    if (_pipe) {
+      copiedPipe = _pipe;
+    }
+  }
+  [copiedPipe writeValue:data];
+}
+
+- (void)finish {
+  GRXBufferedPipe *copiedPipe = nil;
+  @synchronized(self) {
+    NSAssert(_started, @"Call not started.");
+    NSAssert(!_canceled, @"Call already canceled.");
+    NSAssert(!_finished, @"Call already half-closed.");
+    if (!_started) {
+      return;
+    }
+    if (_canceled) {
+      return;
+    }
+    if (_finished) {
+      return;
+    }
+
+    if (_pipe) {
+      copiedPipe = _pipe;
+      _pipe = nil;
+    }
+    _finished = YES;
+  }
+  [copiedPipe writesFinishedWithError:nil];
+}
+
+- (void)issueInitialMetadata:(NSDictionary *)initialMetadata {
+  @synchronized(self) {
+    if (initialMetadata != nil &&
+        [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
+      id<GRPCResponseHandler> copiedHandler = _handler;
+      dispatch_async(_handler.dispatchQueue, ^{
+        [copiedHandler didReceiveInitialMetadata:initialMetadata];
+      });
+    }
+  }
+}
+
+- (void)issueMessage:(id)message {
+  @synchronized(self) {
+    if (message != nil) {
+      if ([_handler respondsToSelector:@selector(didReceiveData:)]) {
+        id<GRPCResponseHandler> copiedHandler = _handler;
+        dispatch_async(_handler.dispatchQueue, ^{
+          [copiedHandler didReceiveData:message];
+        });
+      } else if ([_handler respondsToSelector:@selector(didReceiveRawMessage:)]) {
+        id<GRPCResponseHandler> copiedHandler = _handler;
+        dispatch_async(_handler.dispatchQueue, ^{
+          [copiedHandler didReceiveRawMessage:message];
+        });
+      }
+    }
+  }
+}
+
+- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  @synchronized(self) {
+    if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
+      id<GRPCResponseHandler> copiedHandler = _handler;
+      // Clean up _handler so that no more responses are reported to the handler.
+      _handler = nil;
+      dispatch_async(copiedHandler.dispatchQueue, ^{
+        [copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error];
+      });
+    } else {
+      _handler = nil;
+    }
+  }
+}
+
+- (void)issueDidWriteData {
+  @synchronized(self) {
+    if (_callOptions.flowControlEnabled && [_handler respondsToSelector:@selector(didWriteData)]) {
+      id<GRPCResponseHandler> copiedHandler = _handler;
+      dispatch_async(copiedHandler.dispatchQueue, ^{
+        [copiedHandler didWriteData];
+      });
+    }
+  }
+}
+
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
+  // branching based on _callOptions.flowControlEnabled is handled inside _call
+  GRPCCall *copiedCall = nil;
+  @synchronized(self) {
+    copiedCall = _call;
+    if (copiedCall == nil) {
+      _pendingReceiveNextMessages += numberOfMessages;
+      return;
+    }
+  }
+  [copiedCall receiveNextMessages:numberOfMessages];
+}
+
+@end
index 20cf2ac..a162f1b 100644 (file)
@@ -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.21.3"
+#define GRPC_OBJC_VERSION_STRING @"1.22.0"
index 80988be..4700fdd 100644 (file)
@@ -224,11 +224,11 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
   }
 }
 
-- (void)didReceiveRawMessage:(NSData *)message {
-  if (message == nil) return;
+- (void)didReceiveData:(id)data {
+  if (data == nil) return;
 
   NSError *error = nil;
-  GPBMessage *parsed = [_responseClass parseFromData:message error:&error];
+  GPBMessage *parsed = [_responseClass parseFromData:data error:&error];
   @synchronized(self) {
     if (parsed && [_handler respondsToSelector:@selector(didReceiveProtoMessage:)]) {
       dispatch_async(_dispatchQueue, ^{
@@ -248,7 +248,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
         }
         [copiedHandler
             didCloseWithTrailingMetadata:nil
-                                   error:ErrorForBadProto(message, self->_responseClass, error)];
+                                   error:ErrorForBadProto(data, self->_responseClass, error)];
       });
       [_call cancel];
       _call = nil;
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample.xcodeproj/project.pbxproj b/src/objective-c/examples/InterceptorSample/InterceptorSample.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..8b8811d
--- /dev/null
@@ -0,0 +1,416 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 50;
+       objects = {
+
+/* Begin PBXBuildFile section */
+               1C4854A76EEB56F8096DBDEF /* libPods-InterceptorSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB7A7A5B91FC976FCF4637AE /* libPods-InterceptorSample.a */; };
+               5EE960FB2266768A0044A74F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE960FA2266768A0044A74F /* AppDelegate.m */; };
+               5EE960FE2266768A0044A74F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE960FD2266768A0044A74F /* ViewController.m */; };
+               5EE961012266768A0044A74F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EE960FF2266768A0044A74F /* Main.storyboard */; };
+               5EE961032266768C0044A74F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EE961022266768C0044A74F /* Assets.xcassets */; };
+               5EE961062266768C0044A74F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EE961042266768C0044A74F /* LaunchScreen.storyboard */; };
+               5EE961092266768C0044A74F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE961082266768C0044A74F /* main.m */; };
+               5EE9611222668CF20044A74F /* CacheInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE9611122668CF20044A74F /* CacheInterceptor.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+               09457A264AAE5323BF50B1F8 /* Pods-InterceptorSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InterceptorSample.debug.xcconfig"; path = "Target Support Files/Pods-InterceptorSample/Pods-InterceptorSample.debug.xcconfig"; sourceTree = "<group>"; };
+               5EE960F62266768A0044A74F /* InterceptorSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InterceptorSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+               5EE960FA2266768A0044A74F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+               5EE960FC2266768A0044A74F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+               5EE960FD2266768A0044A74F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+               5EE961002266768A0044A74F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+               5EE961022266768C0044A74F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+               5EE961052266768C0044A74F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+               5EE961072266768C0044A74F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               5EE961082266768C0044A74F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+               5EE9610F2266774C0044A74F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+               5EE9611022668CE20044A74F /* CacheInterceptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheInterceptor.h; sourceTree = "<group>"; };
+               5EE9611122668CF20044A74F /* CacheInterceptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CacheInterceptor.m; sourceTree = "<group>"; };
+               A0789280A4035D0F22F96BE6 /* Pods-InterceptorSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InterceptorSample.release.xcconfig"; path = "Target Support Files/Pods-InterceptorSample/Pods-InterceptorSample.release.xcconfig"; sourceTree = "<group>"; };
+               CB7A7A5B91FC976FCF4637AE /* libPods-InterceptorSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InterceptorSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               5EE960F32266768A0044A74F /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1C4854A76EEB56F8096DBDEF /* libPods-InterceptorSample.a in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               5EE960ED2266768A0044A74F = {
+                       isa = PBXGroup;
+                       children = (
+                               5EE960F82266768A0044A74F /* InterceptorSample */,
+                               5EE960F72266768A0044A74F /* Products */,
+                               9D49DB75F3BEDAFDE7028B51 /* Pods */,
+                               BD7184728351C7DDAFBA5FA2 /* Frameworks */,
+                       );
+                       sourceTree = "<group>";
+               };
+               5EE960F72266768A0044A74F /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5EE960F62266768A0044A74F /* InterceptorSample.app */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               5EE960F82266768A0044A74F /* InterceptorSample */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5EE960FA2266768A0044A74F /* AppDelegate.m */,
+                               5EE960FC2266768A0044A74F /* ViewController.h */,
+                               5EE960FD2266768A0044A74F /* ViewController.m */,
+                               5EE960FF2266768A0044A74F /* Main.storyboard */,
+                               5EE961022266768C0044A74F /* Assets.xcassets */,
+                               5EE961042266768C0044A74F /* LaunchScreen.storyboard */,
+                               5EE961072266768C0044A74F /* Info.plist */,
+                               5EE961082266768C0044A74F /* main.m */,
+                               5EE9610F2266774C0044A74F /* AppDelegate.h */,
+                               5EE9611022668CE20044A74F /* CacheInterceptor.h */,
+                               5EE9611122668CF20044A74F /* CacheInterceptor.m */,
+                       );
+                       path = InterceptorSample;
+                       sourceTree = "<group>";
+               };
+               9D49DB75F3BEDAFDE7028B51 /* Pods */ = {
+                       isa = PBXGroup;
+                       children = (
+                               09457A264AAE5323BF50B1F8 /* Pods-InterceptorSample.debug.xcconfig */,
+                               A0789280A4035D0F22F96BE6 /* Pods-InterceptorSample.release.xcconfig */,
+                       );
+                       path = Pods;
+                       sourceTree = "<group>";
+               };
+               BD7184728351C7DDAFBA5FA2 /* Frameworks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               CB7A7A5B91FC976FCF4637AE /* libPods-InterceptorSample.a */,
+                       );
+                       name = Frameworks;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               5EE960F52266768A0044A74F /* InterceptorSample */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 5EE9610C2266768C0044A74F /* Build configuration list for PBXNativeTarget "InterceptorSample" */;
+                       buildPhases = (
+                               7531607F028A04DAAF5E97B5 /* [CP] Check Pods Manifest.lock */,
+                               5EE960F22266768A0044A74F /* Sources */,
+                               5EE960F32266768A0044A74F /* Frameworks */,
+                               5EE960F42266768A0044A74F /* Resources */,
+                               17700C95BAEBB27F7A3D1B01 /* [CP] Copy Pods Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = InterceptorSample;
+                       productName = InterceptorSample;
+                       productReference = 5EE960F62266768A0044A74F /* InterceptorSample.app */;
+                       productType = "com.apple.product-type.application";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               5EE960EE2266768A0044A74F /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 1010;
+                               ORGANIZATIONNAME = gRPC;
+                               TargetAttributes = {
+                                       5EE960F52266768A0044A74F = {
+                                               CreatedOnToolsVersion = 10.1;
+                                       };
+                               };
+                       };
+                       buildConfigurationList = 5EE960F12266768A0044A74F /* Build configuration list for PBXProject "InterceptorSample" */;
+                       compatibilityVersion = "Xcode 9.3";
+                       developmentRegion = en;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               en,
+                               Base,
+                       );
+                       mainGroup = 5EE960ED2266768A0044A74F;
+                       productRefGroup = 5EE960F72266768A0044A74F /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               5EE960F52266768A0044A74F /* InterceptorSample */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               5EE960F42266768A0044A74F /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5EE961062266768C0044A74F /* LaunchScreen.storyboard in Resources */,
+                               5EE961032266768C0044A74F /* Assets.xcassets in Resources */,
+                               5EE961012266768A0044A74F /* Main.storyboard in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               17700C95BAEBB27F7A3D1B01 /* [CP] Copy Pods Resources */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-InterceptorSample/Pods-InterceptorSample-resources-${CONFIGURATION}-input-files.xcfilelist",
+                       );
+                       name = "[CP] Copy Pods Resources";
+                       outputFileListPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-InterceptorSample/Pods-InterceptorSample-resources-${CONFIGURATION}-output-files.xcfilelist",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-InterceptorSample/Pods-InterceptorSample-resources.sh\"\n";
+                       showEnvVarsInLog = 0;
+               };
+               7531607F028A04DAAF5E97B5 /* [CP] Check Pods Manifest.lock */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+                               "${PODS_ROOT}/Manifest.lock",
+                       );
+                       name = "[CP] Check Pods Manifest.lock";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/Pods-InterceptorSample-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;
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               5EE960F22266768A0044A74F /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5EE9611222668CF20044A74F /* CacheInterceptor.m in Sources */,
+                               5EE960FE2266768A0044A74F /* ViewController.m in Sources */,
+                               5EE961092266768C0044A74F /* main.m in Sources */,
+                               5EE960FB2266768A0044A74F /* AppDelegate.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+               5EE960FF2266768A0044A74F /* Main.storyboard */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               5EE961002266768A0044A74F /* Base */,
+                       );
+                       name = Main.storyboard;
+                       sourceTree = "<group>";
+               };
+               5EE961042266768C0044A74F /* LaunchScreen.storyboard */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               5EE961052266768C0044A74F /* Base */,
+                       );
+                       name = LaunchScreen.storyboard;
+                       sourceTree = "<group>";
+               };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+               5EE9610A2266768C0044A74F /* 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 = "iPhone Developer";
+                               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;
+                               IPHONEOS_DEPLOYMENT_TARGET = 12.1;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = iphoneos;
+                       };
+                       name = Debug;
+               };
+               5EE9610B2266768C0044A74F /* 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 = "iPhone Developer";
+                               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;
+                               IPHONEOS_DEPLOYMENT_TARGET = 12.1;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               MTL_FAST_MATH = YES;
+                               SDKROOT = iphoneos;
+                               VALIDATE_PRODUCT = YES;
+                       };
+                       name = Release;
+               };
+               5EE9610D2266768C0044A74F /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 09457A264AAE5323BF50B1F8 /* Pods-InterceptorSample.debug.xcconfig */;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CODE_SIGN_STYLE = Automatic;
+                               INFOPLIST_FILE = InterceptorSample/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InterceptorSample;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                       };
+                       name = Debug;
+               };
+               5EE9610E2266768C0044A74F /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = A0789280A4035D0F22F96BE6 /* Pods-InterceptorSample.release.xcconfig */;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CODE_SIGN_STYLE = Automatic;
+                               INFOPLIST_FILE = InterceptorSample/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InterceptorSample;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               5EE960F12266768A0044A74F /* Build configuration list for PBXProject "InterceptorSample" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               5EE9610A2266768C0044A74F /* Debug */,
+                               5EE9610B2266768C0044A74F /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               5EE9610C2266768C0044A74F /* Build configuration list for PBXNativeTarget "InterceptorSample" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               5EE9610D2266768C0044A74F /* Debug */,
+                               5EE9610E2266768C0044A74F /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 5EE960EE2266768A0044A74F /* Project object */;
+}
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/AppDelegate.h b/src/objective-c/examples/InterceptorSample/InterceptorSample/AppDelegate.h
new file mode 100644 (file)
index 0000000..183abcf
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright 2019 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 <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder<UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow* window;
+
+@end
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2019 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
-#import <Foundation/Foundation.h>
+#import "AppDelegate.h"
 
-@interface Tests : NSObject
-@end
+@implementation AppDelegate
 
-@implementation Tests
 @end
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644 (file)
index 0000000..d8db8d6
--- /dev/null
@@ -0,0 +1,98 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "83.5x83.5",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ios-marketing",
+      "size" : "1024x1024",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/Contents.json b/src/objective-c/examples/InterceptorSample/InterceptorSample/Assets.xcassets/Contents.json
new file mode 100644 (file)
index 0000000..da4a164
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/LaunchScreen.storyboard b/src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/LaunchScreen.storyboard
new file mode 100644 (file)
index 0000000..bfa3612
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/Main.storyboard b/src/objective-c/examples/InterceptorSample/InterceptorSample/Base.lproj/Main.storyboard
new file mode 100644 (file)
index 0000000..9310a8e
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XDI-qX-FfC">
+                                <rect key="frame" x="172" y="182" width="30" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" title="Call"/>
+                                <connections>
+                                    <action selector="tapCall:" destination="BYZ-38-t0r" eventType="touchUpInside" id="qEz-Hb-ReK"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.h b/src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.h
new file mode 100644 (file)
index 0000000..a1de74c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2019 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 <GRPCClient/GRPCInterceptor.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RequestCacheEntry : NSObject<NSCopying>
+
+@property(readonly, copy, nullable) NSString *path;
+@property(readonly, copy, nullable) id message;
+
+@end
+
+@interface MutableRequestCacheEntry : RequestCacheEntry
+
+@property(copy, nullable) NSString *path;
+@property(copy, nullable) id<NSObject> message;
+
+@end
+
+@interface ResponseCacheEntry : NSObject<NSCopying>
+
+@property(readonly, copy, nullable) NSDate *deadline;
+
+@property(readonly, copy, nullable) NSDictionary *headers;
+@property(readonly, copy, nullable) id message;
+@property(readonly, copy, nullable) NSDictionary *trailers;
+
+@end
+
+@interface MutableResponseCacheEntry : ResponseCacheEntry
+
+@property(copy, nullable) NSDate *deadline;
+
+@property(copy, nullable) NSDictionary *headers;
+@property(copy, nullable) id message;
+@property(copy, nullable) NSDictionary *trailers;
+
+@end
+
+@interface CacheContext : NSObject<GRPCInterceptorFactory>
+
+- (nullable instancetype)init;
+
+- (nullable ResponseCacheEntry *)getCachedResponseForRequest:(RequestCacheEntry *)request;
+
+- (void)setCachedResponse:(ResponseCacheEntry *)response forRequest:(RequestCacheEntry *)request;
+
+@end
+
+@interface CacheInterceptor : GRPCInterceptor
+
+- (instancetype)init NS_UNAVAILABLE;
+
++ (instancetype) new NS_UNAVAILABLE;
+
+- (nullable instancetype)initWithInterceptorManager:
+                             (GRPCInterceptorManager *_Nonnull)intercepterManager
+                                       cacheContext:(CacheContext *_Nonnull)cacheContext
+    NS_DESIGNATED_INITIALIZER;
+
+// implementation of GRPCInterceptorInterface
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions;
+- (void)writeData:(id)data;
+- (void)finish;
+
+// implementation of GRPCResponseHandler
+- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata;
+- (void)didReceiveData:(id)data;
+- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
+                               error:(nullable NSError *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.m b/src/objective-c/examples/InterceptorSample/InterceptorSample/CacheInterceptor.m
new file mode 100644 (file)
index 0000000..c8e584d
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ *
+ * Copyright 2019 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 "CacheInterceptor.h"
+
+@implementation RequestCacheEntry {
+ @protected
+  NSString *_path;
+  id<NSObject> _message;
+}
+
+@synthesize path = _path;
+@synthesize message = _message;
+
+- (instancetype)initWithPath:(NSString *)path message:(id)message {
+  if ((self = [super init])) {
+    _path = [path copy];
+    _message = [message copy];
+  }
+  return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  return [[RequestCacheEntry allocWithZone:zone] initWithPath:_path message:_message];
+}
+
+- (BOOL)isEqual:(id)object {
+  if ([self class] != [object class]) return NO;
+  RequestCacheEntry *rhs = (RequestCacheEntry *)object;
+  return ([_path isEqualToString:rhs.path] && [_message isEqual:rhs.message]);
+}
+
+- (NSUInteger)hash {
+  return _path.hash ^ _message.hash;
+}
+
+@end
+
+@implementation MutableRequestCacheEntry
+
+@dynamic path;
+@dynamic message;
+
+- (void)setPath:(NSString *)path {
+  _path = [path copy];
+}
+
+- (void)setMessage:(id)message {
+  _message = [message copy];
+}
+
+@end
+
+@implementation ResponseCacheEntry {
+ @protected
+  NSDate *_deadline;
+  NSDictionary *_headers;
+  id _message;
+  NSDictionary *_trailers;
+}
+
+@synthesize deadline = _deadline;
+@synthesize headers = _headers;
+@synthesize message = _message;
+@synthesize trailers = _trailers;
+
+- (instancetype)initWithDeadline:(NSDate *)deadline
+                         headers:(NSDictionary *)headers
+                         message:(id)message
+                        trailers:(NSDictionary *)trailers {
+  if (([super init])) {
+    _deadline = [deadline copy];
+    _headers = [[NSDictionary alloc] initWithDictionary:headers copyItems:YES];
+    _message = [message copy];
+    _trailers = [[NSDictionary alloc] initWithDictionary:trailers copyItems:YES];
+  }
+  return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  return [[ResponseCacheEntry allocWithZone:zone] initWithDeadline:_deadline
+                                                           headers:_headers
+                                                           message:_message
+                                                          trailers:_trailers];
+}
+
+@end
+
+@implementation MutableResponseCacheEntry
+
+@dynamic deadline;
+@dynamic headers;
+@dynamic message;
+@dynamic trailers;
+
+- (void)setDeadline:(NSDate *)deadline {
+  _deadline = [deadline copy];
+}
+
+- (void)setHeaders:(NSDictionary *)headers {
+  _headers = [[NSDictionary alloc] initWithDictionary:headers copyItems:YES];
+}
+
+- (void)setMessage:(id)message {
+  _message = [message copy];
+}
+
+- (void)setTrailers:(NSDictionary *)trailers {
+  _trailers = [[NSDictionary alloc] initWithDictionary:trailers copyItems:YES];
+}
+
+@end
+
+@implementation CacheContext {
+  NSCache<RequestCacheEntry *, ResponseCacheEntry *> *_cache;
+}
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    _cache = [[NSCache alloc] init];
+  }
+  return self;
+}
+
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
+  return [[CacheInterceptor alloc] initWithInterceptorManager:interceptorManager cacheContext:self];
+}
+
+- (ResponseCacheEntry *)getCachedResponseForRequest:(RequestCacheEntry *)request {
+  ResponseCacheEntry *response = nil;
+  @synchronized(self) {
+    response = [_cache objectForKey:request];
+    if ([response.deadline timeIntervalSinceNow] < 0) {
+      [_cache removeObjectForKey:request];
+      response = nil;
+    }
+  }
+  return response;
+}
+
+- (void)setCachedResponse:(ResponseCacheEntry *)response forRequest:(RequestCacheEntry *)request {
+  @synchronized(self) {
+    [_cache setObject:response forKey:request];
+  }
+}
+
+@end
+
+@implementation CacheInterceptor {
+  GRPCInterceptorManager *_manager;
+  CacheContext *_context;
+  dispatch_queue_t _dispatchQueue;
+
+  BOOL _cacheable;
+  BOOL _writeMessageSeen;
+  BOOL _readMessageSeen;
+  GRPCCallOptions *_callOptions;
+  GRPCRequestOptions *_requestOptions;
+  id _requestMessage;
+  MutableRequestCacheEntry *_request;
+  MutableResponseCacheEntry *_response;
+}
+
+- (dispatch_queue_t)requestDispatchQueue {
+  return _dispatchQueue;
+}
+
+- (dispatch_queue_t)dispatchQueue {
+  return _dispatchQueue;
+}
+
+- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *_Nonnull)intercepterManager
+                              cacheContext:(CacheContext *_Nonnull)cacheContext {
+  if ((self = [super initWithInterceptorManager:intercepterManager
+                           requestDispatchQueue:dispatch_get_main_queue()
+                          responseDispatchQueue:dispatch_get_main_queue()])) {
+    _manager = intercepterManager;
+    _context = cacheContext;
+    _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+
+    _cacheable = YES;
+    _writeMessageSeen = NO;
+    _readMessageSeen = NO;
+    _request = nil;
+    _response = nil;
+  }
+  return self;
+}
+
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions {
+  if (requestOptions.safety != GRPCCallSafetyCacheableRequest) {
+    _cacheable = NO;
+    [_manager startNextInterceptorWithRequest:requestOptions callOptions:callOptions];
+  } else {
+    _requestOptions = [requestOptions copy];
+    _callOptions = [callOptions copy];
+  }
+}
+
+- (void)writeData:(id)data {
+  if (!_cacheable) {
+    [_manager writeNextInterceptorWithData:data];
+  } else {
+    NSAssert(!_writeMessageSeen, @"CacheInterceptor does not support streaming call");
+    if (_writeMessageSeen) {
+      NSLog(@"CacheInterceptor does not support streaming call");
+    }
+    _writeMessageSeen = YES;
+    _requestMessage = [data copy];
+  }
+}
+
+- (void)finish {
+  if (!_cacheable) {
+    [_manager finishNextInterceptor];
+  } else {
+    _request = [[MutableRequestCacheEntry alloc] init];
+    _request.path = _requestOptions.path;
+    _request.message = [_requestMessage copy];
+    _response = [[_context getCachedResponseForRequest:_request] copy];
+    if (!_response) {
+      [_manager startNextInterceptorWithRequest:_requestOptions callOptions:_callOptions];
+      [_manager writeNextInterceptorWithData:_requestMessage];
+      [_manager finishNextInterceptor];
+    } else {
+      [_manager forwardPreviousInterceptorWithInitialMetadata:_response.headers];
+      [_manager forwardPreviousInterceptorWithData:_response.message];
+      [_manager forwardPreviousInterceptorCloseWithTrailingMetadata:_response.trailers error:nil];
+      [_manager shutDown];
+    }
+  }
+}
+
+- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
+  if (_cacheable) {
+    NSDate *deadline = nil;
+    for (NSString *key in initialMetadata) {
+      if ([key.lowercaseString isEqualToString:@"cache-control"]) {
+        NSArray *cacheControls = [initialMetadata[key] componentsSeparatedByString:@","];
+        for (NSString *option in cacheControls) {
+          NSString *trimmedOption =
+              [option stringByTrimmingCharactersInSet:[NSCharacterSet
+                                                          characterSetWithCharactersInString:@" "]];
+          if ([trimmedOption.lowercaseString isEqualToString:@"no-cache"] ||
+              [trimmedOption.lowercaseString isEqualToString:@"no-store"] ||
+              [trimmedOption.lowercaseString isEqualToString:@"no-transform"]) {
+            _cacheable = NO;
+            break;
+          } else if ([trimmedOption.lowercaseString hasPrefix:@"max-age="]) {
+            NSArray<NSString *> *components = [trimmedOption componentsSeparatedByString:@"="];
+            if (components.count == 2) {
+              NSUInteger maxAge = components[1].intValue;
+              deadline = [NSDate dateWithTimeIntervalSinceNow:maxAge];
+            }
+          }
+        }
+      }
+    }
+    if (_cacheable) {
+      _response = [[MutableResponseCacheEntry alloc] init];
+      _response.headers = [initialMetadata copy];
+      _response.deadline = deadline;
+    }
+  }
+  [_manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
+}
+
+- (void)didReceiveData:(id)data {
+  if (_cacheable) {
+    NSAssert(!_readMessageSeen, @"CacheInterceptor does not support streaming call");
+    if (_readMessageSeen) {
+      NSLog(@"CacheInterceptor does not support streaming call");
+    }
+    _readMessageSeen = YES;
+    _response.message = [data copy];
+  }
+  [_manager forwardPreviousInterceptorWithData:data];
+}
+
+- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  if (error == nil && _cacheable) {
+    _response.trailers = [trailingMetadata copy];
+    [_context setCachedResponse:_response forRequest:_request];
+    NSLog(@"Write cache for %@", _request);
+  }
+  [_manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata error:error];
+  [_manager shutDown];
+}
+
+@end
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/Info.plist b/src/objective-c/examples/InterceptorSample/InterceptorSample/Info.plist
new file mode 100644 (file)
index 0000000..16be3b6
--- /dev/null
@@ -0,0 +1,45 @@
+<?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>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>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>UILaunchStoryboardName</key>
+       <string>LaunchScreen</string>
+       <key>UIMainStoryboardFile</key>
+       <string>Main</string>
+       <key>UIRequiredDeviceCapabilities</key>
+       <array>
+               <string>armv7</string>
+       </array>
+       <key>UISupportedInterfaceOrientations</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+       <key>UISupportedInterfaceOrientations~ipad</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationPortraitUpsideDown</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+</dict>
+</plist>
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.h b/src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.h
new file mode 100644 (file)
index 0000000..0aa0b2a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright 2019 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 <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.m b/src/objective-c/examples/InterceptorSample/InterceptorSample/ViewController.m
new file mode 100644 (file)
index 0000000..9da6ded
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2019 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"
+
+#import <GRPCClient/GRPCCall.h>
+#import <RemoteTest/Messages.pbobjc.h>
+#import <RemoteTest/Test.pbrpc.h>
+
+#import "CacheInterceptor.h"
+
+static NSString *const kPackage = @"grpc.testing";
+static NSString *const kService = @"TestService";
+
+@interface ViewController ()<GRPCResponseHandler>
+
+@end
+
+@implementation ViewController {
+  GRPCCallOptions *_options;
+}
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+
+  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
+
+  id<GRPCInterceptorFactory> factory = [[CacheContext alloc] init];
+  options.interceptorFactories = @[ factory ];
+  _options = options;
+}
+
+- (IBAction)tapCall:(id)sender {
+  GRPCProtoMethod *kUnaryCallMethod =
+      [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"];
+
+  GRPCRequestOptions *requestOptions =
+      [[GRPCRequestOptions alloc] initWithHost:@"grpc-test.sandbox.googleapis.com"
+                                          path:kUnaryCallMethod.HTTPPath
+                                        safety:GRPCCallSafetyCacheableRequest];
+
+  GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions
+                                              responseHandler:self
+                                                  callOptions:_options];
+
+  RMTSimpleRequest *request = [RMTSimpleRequest message];
+  request.responseSize = 100;
+
+  [call start];
+  [call writeData:[request data]];
+  [call finish];
+}
+
+- (dispatch_queue_t)dispatchQueue {
+  return dispatch_get_main_queue();
+}
+
+- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
+  NSLog(@"Header: %@", initialMetadata);
+}
+
+- (void)didReceiveData:(id)data {
+  NSLog(@"Message: %@", data);
+}
+
+- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  NSLog(@"Trailer: %@\nError: %@", trailingMetadata, error);
+}
+
+@end
diff --git a/src/objective-c/examples/InterceptorSample/InterceptorSample/main.m b/src/objective-c/examples/InterceptorSample/InterceptorSample/main.m
new file mode 100644 (file)
index 0000000..2797c6f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright 2019 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 <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+  }
+}
diff --git a/src/objective-c/examples/InterceptorSample/Podfile b/src/objective-c/examples/InterceptorSample/Podfile
new file mode 100644 (file)
index 0000000..b20813d
--- /dev/null
@@ -0,0 +1,31 @@
+platform :ios, '8.0'
+
+install! 'cocoapods', :deterministic_uuids => false
+
+ROOT_DIR = '../../../..'
+
+target 'InterceptorSample' do
+  pod 'gRPC-ProtoRPC', :path => ROOT_DIR
+  pod 'gRPC', :path => ROOT_DIR
+  pod 'gRPC-Core', :path => ROOT_DIR
+  pod 'gRPC-RxLibrary', :path => ROOT_DIR
+  pod 'RemoteTest', :path => "../RemoteTestClient"
+  pod '!ProtoCompiler-gRPCPlugin', :path => "#{ROOT_DIR}/src/objective-c"
+end
+
+pre_install do |installer|
+  grpc_core_spec = installer.pod_targets.find{|t| t.name.start_with?('gRPC-Core')}.root_spec
+
+  src_root = "$(PODS_TARGET_SRCROOT)"
+  grpc_core_spec.pod_target_xcconfig = {
+    'GRPC_SRC_ROOT' => src_root,
+    'HEADER_SEARCH_PATHS' => '"$(inherited)" "$(GRPC_SRC_ROOT)/include"',
+    'USER_HEADER_SEARCH_PATHS' => '"$(GRPC_SRC_ROOT)"',
+    # If we don't set these two settings, `include/grpc/support/time.h` and
+    # `src/core/lib/gpr/string.h` shadow the system `<time.h>` and `<string.h>`, breaking the
+    # build.
+    'USE_HEADERMAP' => 'NO',
+    'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+  }
+end
+
diff --git a/src/objective-c/tests/APIv2Tests/Info.plist b/src/objective-c/tests/APIv2Tests/Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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>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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
diff --git a/src/objective-c/tests/ChannelTests/Info.plist b/src/objective-c/tests/ChannelTests/Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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>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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
diff --git a/src/objective-c/tests/ConfigureCronet.h b/src/objective-c/tests/ConfigureCronet.h
new file mode 100644 (file)
index 0000000..cc5c038
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *
+ * Copyright 2019 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.
+ *
+ */
+
+#ifdef GRPC_COMPILE_WITH_CRONET
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Enable Cronet for once.
+ */
+void configureCronet(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/objective-c/tests/ConfigureCronet.m b/src/objective-c/tests/ConfigureCronet.m
new file mode 100644 (file)
index 0000000..ab137e2
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2019 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.
+ *
+ */
+
+#ifdef GRPC_COMPILE_WITH_CRONET
+
+#import "ConfigureCronet.h"
+#import <Cronet/Cronet.h>
+
+void configureCronet(void) {
+  static dispatch_once_t configureCronet;
+  dispatch_once(&configureCronet, ^{
+    NSLog(@"configureCronet()");
+    [Cronet setHttp2Enabled:YES];
+    [Cronet setSslKeyLogFileName:@"Documents/key"];
+    [Cronet enableTestCertVerifierForTesting];
+    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
+                                                         inDomains:NSUserDomainMask] lastObject];
+    NSLog(@"Documents directory: %@", url);
+    [Cronet start];
+    [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
+  });
+}
+
+#endif
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist b/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
deleted file mode 100644 (file)
index fbeeb96..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIdentifier</key>
-       <string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
@@ -49,6 +49,8 @@
 #import <Cronet/Cronet.h>
 #include <grpc/grpc_cronet.h>
 
+#import "../ConfigureCronet.h"
+
 typedef struct fullstack_secure_fixture_data {
   char *localaddr;
 } fullstack_secure_fixture_data;
@@ -176,13 +178,7 @@ static char *roots_filename;
 
   grpc_init();
 
-  [Cronet setHttp2Enabled:YES];
-  [Cronet enableTestCertVerifierForTesting];
-  NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
-                                                       inDomains:NSUserDomainMask] lastObject];
-  NSLog(@"Documents directory: %@", url);
-  [Cronet start];
-  [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
+  configureCronet();
 }
 
 // The tearDown() function is run after all test cases finish running
@@ -20,6 +20,8 @@
 #import <netinet/in.h>
 #import <sys/socket.h>
 
+#import "../ConfigureCronet.h"
+
 #import <Cronet/Cronet.h>
 #import <grpc/grpc.h>
 #import <grpc/grpc_cronet.h>
@@ -37,6 +39,7 @@
 #import "test/core/end2end/data/ssl_test_data.h"
 #import "test/core/util/test_config.h"
 
+#define GRPC_SHADOW_BORINGSSL_SYMBOLS
 #import "src/core/tsi/grpc_shadow_boringssl.h"
 
 #import <openssl_grpc/ssl.h>
@@ -61,16 +64,7 @@ static void drain_cq(grpc_completion_queue *cq) {
   grpc_test_init(1, argv);
 
   grpc_init();
-
-  [Cronet setHttp2Enabled:YES];
-  [Cronet setSslKeyLogFileName:@"Documents/key"];
-  [Cronet enableTestCertVerifierForTesting];
-  NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
-                                                       inDomains:NSUserDomainMask] lastObject];
-  NSLog(@"Documents directory: %@", url);
-  [Cronet start];
-  [Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES];
-
+  configureCronet();
   init_ssl();
 }
 
@@ -44,6 +44,10 @@ static int32_t kRemoteInteropServerOverhead = 12;
   return kRemoteSSLHost;
 }
 
++ (BOOL)useCronet {
+  return YES;
+}
+
 - (int32_t)encodingOverhead {
   return kRemoteInteropServerOverhead;  // bytes
 }
diff --git a/src/objective-c/tests/CronetUnitTests/Info.plist b/src/objective-c/tests/CronetUnitTests/Info.plist
deleted file mode 100644 (file)
index ba72822..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
similarity index 95%
rename from src/objective-c/tests/InteropTests.h
rename to src/objective-c/tests/InteropTests/InteropTests.h
index 038f24b..cffa90a 100644 (file)
@@ -59,4 +59,9 @@
  */
 + (NSString *)hostNameOverride;
 
+/**
+ * Whether to use Cronet for all the v1 API tests in the test suite.
+ */
++ (BOOL)useCronet;
+
 @end
similarity index 62%
rename from src/objective-c/tests/InteropTests.m
rename to src/objective-c/tests/InteropTests/InteropTests.m
index aab38e3..197ab7f 100644 (file)
@@ -26,6 +26,7 @@
 #import <GRPCClient/GRPCCall+ChannelArg.h>
 #import <GRPCClient/GRPCCall+Cronet.h>
 #import <GRPCClient/GRPCCall+Tests.h>
+#import <GRPCClient/GRPCInterceptor.h>
 #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h>
 #import <ProtoRPC/ProtoRPC.h>
 #import <RemoteTest/Messages.pbobjc.h>
@@ -36,6 +37,9 @@
 #import <grpc/grpc.h>
 #import <grpc/support/log.h>
 
+#import "../ConfigureCronet.h"
+#import "InteropTestsBlockCallbacks.h"
+
 #define TEST_TIMEOUT 32
 
 extern const char *kCFStreamVarName;
@@ -76,77 +80,236 @@ BOOL isRemoteInteropTest(NSString *host) {
   return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"];
 }
 
-// Convenience class to use blocks as callbacks
-@interface InteropTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
+@interface DefaultInterceptorFactory : NSObject<GRPCInterceptorFactory>
+
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
+
+@end
+
+@implementation DefaultInterceptorFactory
+
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
+  dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+  return [[GRPCInterceptor alloc] initWithInterceptorManager:interceptorManager
+                                        requestDispatchQueue:queue
+                                       responseDispatchQueue:queue];
+}
+
+@end
+
+@interface HookInterceptorFactory : NSObject<GRPCInterceptorFactory>
+
+- (instancetype)
+initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+       responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
+                   startHook:(void (^)(GRPCRequestOptions *requestOptions,
+                                       GRPCCallOptions *callOptions,
+                                       GRPCInterceptorManager *manager))startHook
+               writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
+                  finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
+     receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
+                                       GRPCInterceptorManager *manager))receiveNextMessagesHook
+          responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
+                                       GRPCInterceptorManager *manager))responseHeaderHook
+            responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
+           responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
+                                       GRPCInterceptorManager *manager))responseCloseHook
+            didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook;
+
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
 
-- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
-                                messageCallback:(void (^)(id))messageCallback
-                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
-                           writeMessageCallback:(void (^)(void))writeMessageCallback;
+@end
 
-- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
-                                messageCallback:(void (^)(id))messageCallback
-                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
+@interface HookIntercetpor : GRPCInterceptor
+
+- (instancetype)
+initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
+      requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+     responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
+                 startHook:(void (^)(GRPCRequestOptions *requestOptions,
+                                     GRPCCallOptions *callOptions,
+                                     GRPCInterceptorManager *manager))startHook
+             writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
+                finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
+   receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
+                                     GRPCInterceptorManager *manager))receiveNextMessagesHook
+        responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
+                                     GRPCInterceptorManager *manager))responseHeaderHook
+          responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
+         responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
+                                     GRPCInterceptorManager *manager))responseCloseHook
+          didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook;
 
 @end
 
-@implementation InteropTestsBlockCallbacks {
-  void (^_initialMetadataCallback)(NSDictionary *);
-  void (^_messageCallback)(id);
-  void (^_closeCallback)(NSDictionary *, NSError *);
-  void (^_writeMessageCallback)(void);
-  dispatch_queue_t _dispatchQueue;
+@implementation HookInterceptorFactory {
+  void (^_startHook)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
+                     GRPCInterceptorManager *manager);
+  void (^_writeDataHook)(id data, GRPCInterceptorManager *manager);
+  void (^_finishHook)(GRPCInterceptorManager *manager);
+  void (^_receiveNextMessagesHook)(NSUInteger numberOfMessages, GRPCInterceptorManager *manager);
+  void (^_responseHeaderHook)(NSDictionary *initialMetadata, GRPCInterceptorManager *manager);
+  void (^_responseDataHook)(id data, GRPCInterceptorManager *manager);
+  void (^_responseCloseHook)(NSDictionary *trailingMetadata, NSError *error,
+                             GRPCInterceptorManager *manager);
+  void (^_didWriteDataHook)(GRPCInterceptorManager *manager);
+  dispatch_queue_t _requestDispatchQueue;
+  dispatch_queue_t _responseDispatchQueue;
 }
 
-- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
-                                messageCallback:(void (^)(id))messageCallback
-                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
-                           writeMessageCallback:(void (^)(void))writeMessageCallback {
+- (instancetype)
+initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+       responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
+                   startHook:(void (^)(GRPCRequestOptions *requestOptions,
+                                       GRPCCallOptions *callOptions,
+                                       GRPCInterceptorManager *manager))startHook
+               writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
+                  finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
+     receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
+                                       GRPCInterceptorManager *manager))receiveNextMessagesHook
+          responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
+                                       GRPCInterceptorManager *manager))responseHeaderHook
+            responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
+           responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
+                                       GRPCInterceptorManager *manager))responseCloseHook
+            didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook {
   if ((self = [super init])) {
-    _initialMetadataCallback = initialMetadataCallback;
-    _messageCallback = messageCallback;
-    _closeCallback = closeCallback;
-    _writeMessageCallback = writeMessageCallback;
-    _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
+    _requestDispatchQueue = requestDispatchQueue;
+    _responseDispatchQueue = responseDispatchQueue;
+    _startHook = startHook;
+    _writeDataHook = writeDataHook;
+    _finishHook = finishHook;
+    _receiveNextMessagesHook = receiveNextMessagesHook;
+    _responseHeaderHook = responseHeaderHook;
+    _responseDataHook = responseDataHook;
+    _responseCloseHook = responseCloseHook;
+    _didWriteDataHook = didWriteDataHook;
   }
   return self;
 }
 
-- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
-                                messageCallback:(void (^)(id))messageCallback
-                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
-  return [self initWithInitialMetadataCallback:initialMetadataCallback
-                               messageCallback:messageCallback
-                                 closeCallback:closeCallback
-                          writeMessageCallback:nil];
+- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
+  return [[HookIntercetpor alloc] initWithInterceptorManager:interceptorManager
+                                        requestDispatchQueue:_requestDispatchQueue
+                                       responseDispatchQueue:_responseDispatchQueue
+                                                   startHook:_startHook
+                                               writeDataHook:_writeDataHook
+                                                  finishHook:_finishHook
+                                     receiveNextMessagesHook:_receiveNextMessagesHook
+                                          responseHeaderHook:_responseHeaderHook
+                                            responseDataHook:_responseDataHook
+                                           responseCloseHook:_responseCloseHook
+                                            didWriteDataHook:_didWriteDataHook];
 }
 
-- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
-  if (_initialMetadataCallback) {
-    _initialMetadataCallback(initialMetadata);
+@end
+
+@implementation HookIntercetpor {
+  void (^_startHook)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
+                     GRPCInterceptorManager *manager);
+  void (^_writeDataHook)(id data, GRPCInterceptorManager *manager);
+  void (^_finishHook)(GRPCInterceptorManager *manager);
+  void (^_receiveNextMessagesHook)(NSUInteger numberOfMessages, GRPCInterceptorManager *manager);
+  void (^_responseHeaderHook)(NSDictionary *initialMetadata, GRPCInterceptorManager *manager);
+  void (^_responseDataHook)(id data, GRPCInterceptorManager *manager);
+  void (^_responseCloseHook)(NSDictionary *trailingMetadata, NSError *error,
+                             GRPCInterceptorManager *manager);
+  void (^_didWriteDataHook)(GRPCInterceptorManager *manager);
+  GRPCInterceptorManager *_manager;
+  dispatch_queue_t _requestDispatchQueue;
+  dispatch_queue_t _responseDispatchQueue;
+}
+
+- (dispatch_queue_t)requestDispatchQueue {
+  return _requestDispatchQueue;
+}
+
+- (dispatch_queue_t)dispatchQueue {
+  return _responseDispatchQueue;
+}
+
+- (instancetype)
+initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
+      requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
+     responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
+                 startHook:(void (^)(GRPCRequestOptions *requestOptions,
+                                     GRPCCallOptions *callOptions,
+                                     GRPCInterceptorManager *manager))startHook
+             writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
+                finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
+   receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
+                                     GRPCInterceptorManager *manager))receiveNextMessagesHook
+        responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
+                                     GRPCInterceptorManager *manager))responseHeaderHook
+          responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
+         responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
+                                     GRPCInterceptorManager *manager))responseCloseHook
+          didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook {
+  if ((self = [super initWithInterceptorManager:interceptorManager
+                           requestDispatchQueue:requestDispatchQueue
+                          responseDispatchQueue:responseDispatchQueue])) {
+    _startHook = startHook;
+    _writeDataHook = writeDataHook;
+    _finishHook = finishHook;
+    _receiveNextMessagesHook = receiveNextMessagesHook;
+    _responseHeaderHook = responseHeaderHook;
+    _responseDataHook = responseDataHook;
+    _responseCloseHook = responseCloseHook;
+    _didWriteDataHook = didWriteDataHook;
+    _requestDispatchQueue = requestDispatchQueue;
+    _responseDispatchQueue = responseDispatchQueue;
+    _manager = interceptorManager;
   }
+  return self;
 }
 
-- (void)didReceiveProtoMessage:(GPBMessage *)message {
-  if (_messageCallback) {
-    _messageCallback(message);
+- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
+                    callOptions:(GRPCCallOptions *)callOptions {
+  if (_startHook) {
+    _startHook(requestOptions, callOptions, _manager);
   }
 }
 
-- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
-  if (_closeCallback) {
-    _closeCallback(trailingMetadata, error);
+- (void)writeData:(id)data {
+  if (_writeDataHook) {
+    _writeDataHook(data, _manager);
   }
 }
 
-- (void)didWriteMessage {
-  if (_writeMessageCallback) {
-    _writeMessageCallback();
+- (void)finish {
+  if (_finishHook) {
+    _finishHook(_manager);
   }
 }
 
-- (dispatch_queue_t)dispatchQueue {
-  return _dispatchQueue;
+- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
+  if (_receiveNextMessagesHook) {
+    _receiveNextMessagesHook(numberOfMessages, _manager);
+  }
+}
+
+- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
+  if (_responseHeaderHook) {
+    _responseHeaderHook(initialMetadata, _manager);
+  }
+}
+
+- (void)didReceiveData:(id)data {
+  if (_responseDataHook) {
+    _responseDataHook(data, _manager);
+  }
+}
+
+- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  if (_responseCloseHook) {
+    _responseCloseHook(trailingMetadata, error, _manager);
+  }
+}
+
+- (void)didWriteData {
+  if (_didWriteDataHook) {
+    _didWriteDataHook(_manager);
+  }
 }
 
 @end
@@ -180,13 +343,16 @@ BOOL isRemoteInteropTest(NSString *host) {
   return nil;
 }
 
++ (BOOL)useCronet {
+  return NO;
+}
+
 + (void)setUp {
-  NSLog(@"InteropTest Started, class: %@", [[self class] description]);
 #ifdef GRPC_COMPILE_WITH_CRONET
-  // Cronet setup
-  [Cronet setHttp2Enabled:YES];
-  [Cronet start];
-  [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
+  configureCronet();
+  if ([self useCronet]) {
+    [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
+  }
 #endif
 #ifdef GRPC_CFSTREAM
   setenv(kCFStreamVarName, "1", 1);
@@ -198,6 +364,11 @@ BOOL isRemoteInteropTest(NSString *host) {
 
   [GRPCCall resetHostSettings];
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  [GRPCCall closeOpenConnections];
+#pragma clang diagnostic pop
+
   _service = [[self class] host] ? [RMTTestService serviceWithHost:[[self class] host]] : nil;
 }
 
@@ -535,21 +706,21 @@ BOOL isRemoteInteropTest(NSString *host) {
   XCTAssertNotNil([[self class] host]);
   __weak XCTestExpectation *expectation =
       [self expectationWithDescription:@"HigherResponseSizeLimit"];
+  __block NSError *callError = nil;
 
   RMTSimpleRequest *request = [RMTSimpleRequest message];
   const size_t kPayloadSize = 5 * 1024 * 1024;  // 5MB
   request.responseSize = kPayloadSize;
 
   [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:[[self class] host]];
-
   [_service unaryCallWithRequest:request
                          handler:^(RMTSimpleResponse *response, NSError *error) {
-                           XCTAssertNil(error, @"Finished with unexpected error: %@", error);
-                           XCTAssertEqual(response.payload.body.length, kPayloadSize);
+                           callError = error;
                            [expectation fulfill];
                          }];
 
   [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+  XCTAssertNil(callError, @"Finished with unexpected error: %@", callError);
 }
 
 - (void)testClientStreamingRPC {
@@ -1056,4 +1227,296 @@ BOOL isRemoteInteropTest(NSString *host) {
 }
 #endif
 
+- (void)testDefaultInterceptor {
+  XCTAssertNotNil([[self class] host]);
+  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"];
+
+  NSArray *requests = @[ @27182, @8, @1828, @45904 ];
+  NSArray *responses = @[ @31415, @9, @2653, @58979 ];
+
+  __block int index = 0;
+
+  id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
+                                               requestedResponseSize:responses[index]];
+  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = [[self class] transportType];
+  options.PEMRootCertificates = [[self class] PEMRootCertificates];
+  options.hostNameOverride = [[self class] hostNameOverride];
+  options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init] ];
+
+  __block GRPCStreamingProtoCall *call = [_service
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              XCTAssertLessThan(index, 4,
+                                                                @"More than 4 responses received.");
+                                              id expected = [RMTStreamingOutputCallResponse
+                                                  messageWithPayloadSize:responses[index]];
+                                              XCTAssertEqualObjects(message, expected);
+                                              index += 1;
+                                              if (index < 4) {
+                                                id request = [RMTStreamingOutputCallRequest
+                                                    messageWithPayloadSize:requests[index]
+                                                     requestedResponseSize:responses[index]];
+                                                [call writeMessage:request];
+                                              } else {
+                                                [call finish];
+                                              }
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error,
+                                                           @"Finished with unexpected error: %@",
+                                                           error);
+                                              XCTAssertEqual(index, 4,
+                                                             @"Received %i responses instead of 4.",
+                                                             index);
+                                              [expectation fulfill];
+                                            }]
+                            callOptions:options];
+  [call start];
+  [call writeMessage:request];
+
+  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+}
+
+- (void)testLoggingInterceptor {
+  XCTAssertNotNil([[self class] host]);
+  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"];
+
+  __block NSUInteger startCount = 0;
+  __block NSUInteger writeDataCount = 0;
+  __block NSUInteger finishCount = 0;
+  __block NSUInteger receiveNextMessageCount = 0;
+  __block NSUInteger responseHeaderCount = 0;
+  __block NSUInteger responseDataCount = 0;
+  __block NSUInteger responseCloseCount = 0;
+  __block NSUInteger didWriteDataCount = 0;
+  id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
+      initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
+      responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
+      startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
+                  GRPCInterceptorManager *manager) {
+        startCount++;
+        XCTAssertEqualObjects(requestOptions.host, [[self class] host]);
+        XCTAssertEqualObjects(requestOptions.path, @"/grpc.testing.TestService/FullDuplexCall");
+        XCTAssertEqual(requestOptions.safety, GRPCCallSafetyDefault);
+        [manager startNextInterceptorWithRequest:[requestOptions copy]
+                                     callOptions:[callOptions copy]];
+      }
+      writeDataHook:^(id data, GRPCInterceptorManager *manager) {
+        writeDataCount++;
+        [manager writeNextInterceptorWithData:data];
+      }
+      finishHook:^(GRPCInterceptorManager *manager) {
+        finishCount++;
+        [manager finishNextInterceptor];
+      }
+      receiveNextMessagesHook:^(NSUInteger numberOfMessages, GRPCInterceptorManager *manager) {
+        receiveNextMessageCount++;
+        [manager receiveNextInterceptorMessages:numberOfMessages];
+      }
+      responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
+        responseHeaderCount++;
+        [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
+      }
+      responseDataHook:^(id data, GRPCInterceptorManager *manager) {
+        responseDataCount++;
+        [manager forwardPreviousInterceptorWithData:data];
+      }
+      responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
+                          GRPCInterceptorManager *manager) {
+        responseCloseCount++;
+        [manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata error:error];
+      }
+      didWriteDataHook:^(GRPCInterceptorManager *manager) {
+        didWriteDataCount++;
+        [manager forwardPreviousInterceptorDidWriteData];
+      }];
+
+  NSArray *requests = @[ @1, @2, @3, @4 ];
+  NSArray *responses = @[ @1, @2, @3, @4 ];
+
+  __block int index = 0;
+
+  id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
+                                               requestedResponseSize:responses[index]];
+  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = [[self class] transportType];
+  options.PEMRootCertificates = [[self class] PEMRootCertificates];
+  options.hostNameOverride = [[self class] hostNameOverride];
+  options.flowControlEnabled = YES;
+  options.interceptorFactories = @[ factory ];
+  __block BOOL canWriteData = NO;
+
+  __block GRPCStreamingProtoCall *call = [_service
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              XCTAssertLessThan(index, 4,
+                                                                @"More than 4 responses received.");
+                                              id expected = [RMTStreamingOutputCallResponse
+                                                  messageWithPayloadSize:responses[index]];
+                                              XCTAssertEqualObjects(message, expected);
+                                              index += 1;
+                                              if (index < 4) {
+                                                id request = [RMTStreamingOutputCallRequest
+                                                    messageWithPayloadSize:requests[index]
+                                                     requestedResponseSize:responses[index]];
+                                                XCTAssertTrue(canWriteData);
+                                                canWriteData = NO;
+                                                [call writeMessage:request];
+                                                [call receiveNextMessage];
+                                              } else {
+                                                [call finish];
+                                              }
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error,
+                                                           @"Finished with unexpected error: %@",
+                                                           error);
+                                              XCTAssertEqual(index, 4,
+                                                             @"Received %i responses instead of 4.",
+                                                             index);
+                                              [expectation fulfill];
+                                            }
+                                            writeMessageCallback:^{
+                                              canWriteData = YES;
+                                            }]
+                            callOptions:options];
+  [call start];
+  [call receiveNextMessage];
+  [call writeMessage:request];
+
+  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+  XCTAssertEqual(startCount, 1);
+  XCTAssertEqual(writeDataCount, 4);
+  XCTAssertEqual(finishCount, 1);
+  XCTAssertEqual(receiveNextMessageCount, 4);
+  XCTAssertEqual(responseHeaderCount, 1);
+  XCTAssertEqual(responseDataCount, 4);
+  XCTAssertEqual(responseCloseCount, 1);
+  XCTAssertEqual(didWriteDataCount, 4);
+}
+
+// Chain a default interceptor and a hook interceptor which, after two writes, cancels the call
+// under the hood but forward further data to the user.
+- (void)testHijackingInterceptor {
+  NSUInteger kCancelAfterWrites = 2;
+  XCTAssertNotNil([[self class] host]);
+  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"];
+
+  NSArray *responses = @[ @1, @2, @3, @4 ];
+  __block int index = 0;
+
+  __block NSUInteger startCount = 0;
+  __block NSUInteger writeDataCount = 0;
+  __block NSUInteger finishCount = 0;
+  __block NSUInteger responseHeaderCount = 0;
+  __block NSUInteger responseDataCount = 0;
+  __block NSUInteger responseCloseCount = 0;
+  id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
+      initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
+      responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
+      startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
+                  GRPCInterceptorManager *manager) {
+        startCount++;
+        [manager startNextInterceptorWithRequest:[requestOptions copy]
+                                     callOptions:[callOptions copy]];
+      }
+      writeDataHook:^(id data, GRPCInterceptorManager *manager) {
+        writeDataCount++;
+        if (index < kCancelAfterWrites) {
+          [manager writeNextInterceptorWithData:data];
+        } else if (index == kCancelAfterWrites) {
+          [manager cancelNextInterceptor];
+          [manager forwardPreviousInterceptorWithData:[[RMTStreamingOutputCallResponse
+                                                          messageWithPayloadSize:responses[index]]
+                                                          data]];
+        } else {  // (index > kCancelAfterWrites)
+          [manager forwardPreviousInterceptorWithData:[[RMTStreamingOutputCallResponse
+                                                          messageWithPayloadSize:responses[index]]
+                                                          data]];
+        }
+      }
+      finishHook:^(GRPCInterceptorManager *manager) {
+        finishCount++;
+        // finish must happen after the hijacking, so directly reply with a close
+        [manager forwardPreviousInterceptorCloseWithTrailingMetadata:@{@"grpc-status" : @"0"}
+                                                               error:nil];
+      }
+      receiveNextMessagesHook:nil
+      responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
+        responseHeaderCount++;
+        [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
+      }
+      responseDataHook:^(id data, GRPCInterceptorManager *manager) {
+        responseDataCount++;
+        [manager forwardPreviousInterceptorWithData:data];
+      }
+      responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
+                          GRPCInterceptorManager *manager) {
+        responseCloseCount++;
+        // since we canceled the call, it should return cancel error
+        XCTAssertNil(trailingMetadata);
+        XCTAssertNotNil(error);
+        XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
+      }
+      didWriteDataHook:nil];
+
+  NSArray *requests = @[ @1, @2, @3, @4 ];
+
+  id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
+                                               requestedResponseSize:responses[index]];
+  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = [[self class] transportType];
+  options.PEMRootCertificates = [[self class] PEMRootCertificates];
+  options.hostNameOverride = [[self class] hostNameOverride];
+  options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init], factory ];
+
+  __block GRPCStreamingProtoCall *call = [_service
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              XCTAssertLessThan(index, 4,
+                                                                @"More than 4 responses received.");
+                                              id expected = [RMTStreamingOutputCallResponse
+                                                  messageWithPayloadSize:responses[index]];
+                                              XCTAssertEqualObjects(message, expected);
+                                              index += 1;
+                                              if (index < 4) {
+                                                id request = [RMTStreamingOutputCallRequest
+                                                    messageWithPayloadSize:requests[index]
+                                                     requestedResponseSize:responses[index]];
+                                                [call writeMessage:request];
+                                                [call receiveNextMessage];
+                                              } else {
+                                                [call finish];
+                                              }
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error,
+                                                           @"Finished with unexpected error: %@",
+                                                           error);
+                                              XCTAssertEqual(index, 4,
+                                                             @"Received %i responses instead of 4.",
+                                                             index);
+                                              [expectation fulfill];
+                                            }]
+                            callOptions:options];
+  [call start];
+  [call receiveNextMessage];
+  [call writeMessage:request];
+
+  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+  XCTAssertEqual(startCount, 1);
+  XCTAssertEqual(writeDataCount, 4);
+  XCTAssertEqual(finishCount, 1);
+  XCTAssertEqual(responseHeaderCount, 1);
+  XCTAssertEqual(responseDataCount, 2);
+  XCTAssertEqual(responseCloseCount, 1);
+}
+
 @end
diff --git a/src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.h b/src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.h
new file mode 100644 (file)
index 0000000..fa0b836
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2019 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 <ProtoRPC/ProtoRPC.h>
+
+// Convenience class to use blocks as callbacks
+@interface InteropTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
+
+- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
+                                messageCallback:(void (^)(id))messageCallback
+                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
+                           writeMessageCallback:(void (^)(void))writeMessageCallback;
+
+- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
+                                messageCallback:(void (^)(id))messageCallback
+                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
+
+@end
diff --git a/src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.m b/src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.m
new file mode 100644 (file)
index 0000000..1ab1fa9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2019 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 "InteropTestsBlockCallbacks.h"
+
+@implementation InteropTestsBlockCallbacks {
+  void (^_initialMetadataCallback)(NSDictionary *);
+  void (^_messageCallback)(id);
+  void (^_closeCallback)(NSDictionary *, NSError *);
+  void (^_writeMessageCallback)(void);
+  dispatch_queue_t _dispatchQueue;
+}
+
+- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
+                                messageCallback:(void (^)(id))messageCallback
+                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
+                           writeMessageCallback:(void (^)(void))writeMessageCallback {
+  if ((self = [super init])) {
+    _initialMetadataCallback = initialMetadataCallback;
+    _messageCallback = messageCallback;
+    _closeCallback = closeCallback;
+    _writeMessageCallback = writeMessageCallback;
+    _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
+  }
+  return self;
+}
+
+- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
+                                messageCallback:(void (^)(id))messageCallback
+                                  closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
+  return [self initWithInitialMetadataCallback:initialMetadataCallback
+                               messageCallback:messageCallback
+                                 closeCallback:closeCallback
+                          writeMessageCallback:nil];
+}
+
+- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
+  if (_initialMetadataCallback) {
+    _initialMetadataCallback(initialMetadata);
+  }
+}
+
+- (void)didReceiveProtoMessage:(GPBMessage *)message {
+  if (_messageCallback) {
+    _messageCallback(message);
+  }
+}
+
+- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
+  if (_closeCallback) {
+    _closeCallback(trailingMetadata, error);
+  }
+}
+
+- (void)didWriteMessage {
+  if (_writeMessageCallback) {
+    _writeMessageCallback();
+  }
+}
+
+- (dispatch_queue_t)dispatchQueue {
+  return _dispatchQueue;
+}
+
+@end
diff --git a/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m
new file mode 100644 (file)
index 0000000..14ba287
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ *
+ * 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 <XCTest/XCTest.h>
+
+#ifdef GRPC_COMPILE_WITH_CRONET
+#import <Cronet/Cronet.h>
+#endif
+#import <RemoteTest/Messages.pbobjc.h>
+#import <RemoteTest/Test.pbobjc.h>
+#import <RemoteTest/Test.pbrpc.h>
+#import <RxLibrary/GRXBufferedPipe.h>
+
+#import "../ConfigureCronet.h"
+#import "InteropTestsBlockCallbacks.h"
+
+#define NSStringize_helper(x) #x
+#define NSStringize(x) @NSStringize_helper(x)
+static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
+static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
+static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
+
+static const NSTimeInterval TEST_TIMEOUT = 8000;
+
+@interface RMTStreamingOutputCallRequest (Constructors)
++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
+                 requestedResponseSize:(NSNumber *)responseSize;
+@end
+
+@implementation RMTStreamingOutputCallRequest (Constructors)
++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
+                 requestedResponseSize:(NSNumber *)responseSize {
+  RMTStreamingOutputCallRequest *request = [self message];
+  RMTResponseParameters *parameters = [RMTResponseParameters message];
+  parameters.size = responseSize.intValue;
+  [request.responseParametersArray addObject:parameters];
+  request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
+  return request;
+}
+@end
+
+@interface RMTStreamingOutputCallResponse (Constructors)
++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
+@end
+
+@implementation RMTStreamingOutputCallResponse (Constructors)
++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
+  RMTStreamingOutputCallResponse *response = [self message];
+  response.payload.type = RMTPayloadType_Compressable;
+  response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
+  return response;
+}
+@end
+
+@interface InteropTestsMultipleChannels : XCTestCase
+
+@end
+
+dispatch_once_t initCronet;
+
+@implementation InteropTestsMultipleChannels {
+  RMTTestService *_remoteService;
+  RMTTestService *_remoteCronetService;
+  RMTTestService *_localCleartextService;
+  RMTTestService *_localSSLService;
+}
+
+- (void)setUp {
+  [super setUp];
+
+  self.continueAfterFailure = NO;
+
+  _remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:nil];
+
+  configureCronet();
+
+  // Default stack with remote host
+  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = GRPCTransportTypeCronet;
+  // Cronet stack with remote host
+  _remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:options];
+
+  // Local stack with no SSL
+  options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = GRPCTransportTypeInsecure;
+  _localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost callOptions:options];
+
+  // Local stack with SSL
+  NSBundle *bundle = [NSBundle bundleForClass:[self class]];
+  NSString *certsPath =
+      [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
+  NSError *error = nil;
+  NSString *certs =
+      [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
+  XCTAssertNil(error);
+
+  options = [[GRPCMutableCallOptions alloc] init];
+  options.transportType = GRPCTransportTypeChttp2BoringSSL;
+  options.PEMRootCertificates = certs;
+  options.hostNameOverride = @"foo.test.google.fr";
+  _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost callOptions:options];
+}
+
+- (void)testEmptyUnaryRPC {
+  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectCronetRemote =
+      [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectCleartext =
+      [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
+
+  GPBEmpty *request = [GPBEmpty message];
+
+  void (^messageHandler)(id message) = ^(id message) {
+    id expectedResponse = [GPBEmpty message];
+    XCTAssertEqualObjects(message, expectedResponse);
+  };
+
+  GRPCUnaryProtoCall *callRemote = [_remoteService
+      emptyCallWithMessage:request
+           responseHandler:[[InteropTestsBlockCallbacks alloc]
+                               initWithInitialMetadataCallback:nil
+                                               messageCallback:messageHandler
+                                                 closeCallback:^(NSDictionary *trailingMetadata,
+                                                                 NSError *error) {
+                                                   XCTAssertNil(error);
+                                                   [expectRemote fulfill];
+                                                 }
+                                          writeMessageCallback:nil]
+               callOptions:nil];
+  GRPCUnaryProtoCall *callCronet = [_remoteCronetService
+      emptyCallWithMessage:request
+           responseHandler:[[InteropTestsBlockCallbacks alloc]
+                               initWithInitialMetadataCallback:nil
+                                               messageCallback:messageHandler
+                                                 closeCallback:^(NSDictionary *trailingMetadata,
+                                                                 NSError *error) {
+                                                   XCTAssertNil(error);
+                                                   [expectCronetRemote fulfill];
+                                                 }
+                                          writeMessageCallback:nil]
+               callOptions:nil];
+  GRPCUnaryProtoCall *callCleartext = [_localCleartextService
+      emptyCallWithMessage:request
+           responseHandler:[[InteropTestsBlockCallbacks alloc]
+                               initWithInitialMetadataCallback:nil
+                                               messageCallback:messageHandler
+                                                 closeCallback:^(NSDictionary *trailingMetadata,
+                                                                 NSError *error) {
+                                                   XCTAssertNil(error);
+                                                   [expectCleartext fulfill];
+                                                 }
+                                          writeMessageCallback:nil]
+               callOptions:nil];
+  GRPCUnaryProtoCall *callSSL = [_localSSLService
+      emptyCallWithMessage:request
+           responseHandler:[[InteropTestsBlockCallbacks alloc]
+                               initWithInitialMetadataCallback:nil
+                                               messageCallback:messageHandler
+                                                 closeCallback:^(NSDictionary *trailingMetadata,
+                                                                 NSError *error) {
+                                                   XCTAssertNil(error);
+                                                   [expectSSL fulfill];
+                                                 }
+                                          writeMessageCallback:nil]
+               callOptions:nil];
+  [callRemote start];
+  [callCronet start];
+  [callCleartext start];
+  [callSSL start];
+
+  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+}
+
+- (void)testFullDuplexRPC {
+  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectCronetRemote =
+      [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectCleartext =
+      [self expectationWithDescription:@"Remote RPC finish"];
+  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
+
+  NSArray *requestSizes = @[ @100, @101, @102, @103 ];
+  NSArray *responseSizes = @[ @104, @105, @106, @107 ];
+  XCTAssertEqual([requestSizes count], [responseSizes count]);
+  NSUInteger kRounds = [requestSizes count];
+  NSMutableArray<GRPCStreamingProtoCall *> *calls = [NSMutableArray arrayWithCapacity:4];
+
+  NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
+  NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
+  for (int i = 0; i < kRounds; i++) {
+    requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
+                                                  requestedResponseSize:responseSizes[i]];
+    responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
+  }
+
+  __block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
+  __block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
+  for (int i = 0; i < 4; i++) {
+    steps[i] = [NSNumber numberWithUnsignedInteger:0];
+    requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
+    [requestsBuffers[i] writeValue:requests[0]];
+  }
+
+  void (^handler)(NSUInteger index, id message) = ^(NSUInteger index, id message) {
+    NSUInteger step = [steps[index] unsignedIntegerValue];
+    step++;
+    steps[index] = [NSNumber numberWithUnsignedInteger:step];
+    if (step < kRounds) {
+      [calls[index] writeMessage:requests[step]];
+    } else {
+      [calls[index] finish];
+    }
+  };
+
+  calls[0] = [_remoteService
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              handler(0, message);
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error);
+                                              [expectRemote fulfill];
+                                            }
+                                            writeMessageCallback:nil]
+                            callOptions:nil];
+  calls[1] = [_remoteCronetService
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              handler(1, message);
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error);
+                                              [expectCronetRemote fulfill];
+                                            }
+                                            writeMessageCallback:nil]
+                            callOptions:nil];
+  calls[2] = [_localCleartextService
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              handler(2, message);
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error);
+                                              [expectCleartext fulfill];
+                                            }
+                                            writeMessageCallback:nil]
+                            callOptions:nil];
+  calls[3] = [_localSSLService
+      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
+                                            initWithInitialMetadataCallback:nil
+                                            messageCallback:^(id message) {
+                                              handler(3, message);
+                                            }
+                                            closeCallback:^(NSDictionary *trailingMetadata,
+                                                            NSError *error) {
+                                              XCTAssertNil(error);
+                                              [expectSSL fulfill];
+                                            }
+                                            writeMessageCallback:nil]
+                            callOptions:nil];
+  for (int i = 0; i < 4; i++) {
+    [calls[i] start];
+    [calls[i] writeMessage:requests[0]];
+  }
+
+  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+}
+
+@end
diff --git a/src/objective-c/tests/InteropTestsCallOptions/Info.plist b/src/objective-c/tests/InteropTestsCallOptions/Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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>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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
diff --git a/src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m b/src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m
deleted file mode 100644 (file)
index db51cb1..0000000
+++ /dev/null
@@ -1,116 +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.
- *
- */
-
-#import <XCTest/XCTest.h>
-
-#import <RemoteTest/Messages.pbobjc.h>
-#import <RemoteTest/Test.pbobjc.h>
-#import <RemoteTest/Test.pbrpc.h>
-#import <RxLibrary/GRXBufferedPipe.h>
-#import <RxLibrary/GRXWriter+Immediate.h>
-#import <grpc/grpc.h>
-
-#define NSStringize_helper(x) #x
-#define NSStringize(x) @NSStringize_helper(x)
-static NSString *kRemoteHost = NSStringize(HOST_PORT_REMOTE);
-const int32_t kRemoteInteropServerOverhead = 12;
-
-static const NSTimeInterval TEST_TIMEOUT = 16000;
-
-@interface InteropTestsCallOptions : XCTestCase
-
-@end
-
-@implementation InteropTestsCallOptions {
-  RMTTestService *_service;
-}
-
-- (void)setUp {
-  self.continueAfterFailure = NO;
-  _service = [RMTTestService serviceWithHost:kRemoteHost];
-  _service.options = [[GRPCCallOptions alloc] init];
-}
-
-- (void)test4MBResponsesAreAccepted {
-  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
-
-  RMTSimpleRequest *request = [RMTSimpleRequest message];
-  const int32_t kPayloadSize =
-      4 * 1024 * 1024 - kRemoteInteropServerOverhead;  // 4MB - encoding overhead
-  request.responseSize = kPayloadSize;
-
-  [_service unaryCallWithRequest:request
-                         handler:^(RMTSimpleResponse *response, NSError *error) {
-                           XCTAssertNil(error, @"Finished with unexpected error: %@", error);
-                           XCTAssertEqual(response.payload.body.length, kPayloadSize);
-                           [expectation fulfill];
-                         }];
-
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
-}
-
-- (void)testResponsesOverMaxSizeFailWithActionableMessage {
-  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
-
-  RMTSimpleRequest *request = [RMTSimpleRequest message];
-  const int32_t kPayloadSize =
-      4 * 1024 * 1024 - kRemoteInteropServerOverhead + 1;  // 1B over max size
-  request.responseSize = kPayloadSize;
-
-  [_service unaryCallWithRequest:request
-                         handler:^(RMTSimpleResponse *response, NSError *error) {
-                           XCTAssertEqualObjects(
-                               error.localizedDescription,
-                               @"Received message larger than max (4194305 vs. 4194304)");
-                           [expectation fulfill];
-                         }];
-
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
-}
-
-- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
-  __weak XCTestExpectation *expectation =
-      [self expectationWithDescription:@"HigherResponseSizeLimit"];
-
-  RMTSimpleRequest *request = [RMTSimpleRequest message];
-  const size_t kPayloadSize = 5 * 1024 * 1024;  // 5MB
-  request.responseSize = kPayloadSize;
-
-  GRPCProtoCall *rpc = [_service
-      RPCToUnaryCallWithRequest:request
-                        handler:^(RMTSimpleResponse *response, NSError *error) {
-                          XCTAssertNil(error, @"Finished with unexpected error: %@", error);
-                          XCTAssertEqual(response.payload.body.length, kPayloadSize);
-                          [expectation fulfill];
-                        }];
-  GRPCCallOptions *options = rpc.options;
-  options.responseSizeLimit = 6 * 1024 * 1024;
-
-  [rpc start];
-
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
-}
-
-- (void)testPerformanceExample {
-  // This is an example of a performance test case.
-  [self measureBlock:^{
-      // Put the code you want to measure the time of here.
-  }];
-}
-
-@end
diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/Info.plist b/src/objective-c/tests/InteropTestsMultipleChannels/Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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>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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m
deleted file mode 100644 (file)
index b0d4e48..0000000
+++ /dev/null
@@ -1,259 +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.
- *
- */
-
-#import <XCTest/XCTest.h>
-
-#import <Cronet/Cronet.h>
-#import <RemoteTest/Messages.pbobjc.h>
-#import <RemoteTest/Test.pbobjc.h>
-#import <RemoteTest/Test.pbrpc.h>
-#import <RxLibrary/GRXBufferedPipe.h>
-
-#define NSStringize_helper(x) #x
-#define NSStringize(x) @NSStringize_helper(x)
-static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
-static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
-static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
-
-static const NSTimeInterval TEST_TIMEOUT = 8000;
-
-@interface RMTStreamingOutputCallRequest (Constructors)
-+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
-                 requestedResponseSize:(NSNumber *)responseSize;
-@end
-
-@implementation RMTStreamingOutputCallRequest (Constructors)
-+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
-                 requestedResponseSize:(NSNumber *)responseSize {
-  RMTStreamingOutputCallRequest *request = [self message];
-  RMTResponseParameters *parameters = [RMTResponseParameters message];
-  parameters.size = responseSize.intValue;
-  [request.responseParametersArray addObject:parameters];
-  request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
-  return request;
-}
-@end
-
-@interface RMTStreamingOutputCallResponse (Constructors)
-+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
-@end
-
-@implementation RMTStreamingOutputCallResponse (Constructors)
-+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
-  RMTStreamingOutputCallResponse *response = [self message];
-  response.payload.type = RMTPayloadType_Compressable;
-  response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
-  return response;
-}
-@end
-
-@interface InteropTestsMultipleChannels : XCTestCase
-
-@end
-
-dispatch_once_t initCronet;
-
-@implementation InteropTestsMultipleChannels {
-  RMTTestService *_remoteService;
-  RMTTestService *_remoteCronetService;
-  RMTTestService *_localCleartextService;
-  RMTTestService *_localSSLService;
-}
-
-- (void)setUp {
-  [super setUp];
-
-  self.continueAfterFailure = NO;
-
-  // Default stack with remote host
-  _remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost];
-
-  // Cronet stack with remote host
-  _remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost];
-
-  dispatch_once(&initCronet, ^{
-    [Cronet setHttp2Enabled:YES];
-    [Cronet start];
-  });
-
-  GRPCCallOptions *options = [[GRPCCallOptions alloc] init];
-  options.transportType = GRPCTransportTypeCronet;
-  options.cronetEngine = [Cronet getGlobalEngine];
-  _remoteCronetService.options = options;
-
-  // Local stack with no SSL
-  _localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost];
-  options = [[GRPCCallOptions alloc] init];
-  options.transportType = GRPCTransportTypeInsecure;
-  _localCleartextService.options = options;
-
-  // Local stack with SSL
-  _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost];
-
-  NSBundle *bundle = [NSBundle bundleForClass:[self class]];
-  NSString *certsPath =
-      [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
-  NSError *error = nil;
-  NSString *certs =
-      [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
-  XCTAssertNil(error);
-
-  options = [[GRPCCallOptions alloc] init];
-  options.transportType = GRPCTransportTypeChttp2BoringSSL;
-  options.PEMRootCertificates = certs;
-  options.hostNameOverride = @"foo.test.google.fr";
-  _localSSLService.options = options;
-}
-
-- (void)testEmptyUnaryRPC {
-  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectCronetRemote =
-      [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectCleartext =
-      [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
-
-  GPBEmpty *request = [GPBEmpty message];
-
-  void (^handler)(GPBEmpty *response, NSError *error) = ^(GPBEmpty *response, NSError *error) {
-    XCTAssertNil(error, @"Finished with unexpected error: %@", error);
-
-    id expectedResponse = [GPBEmpty message];
-    XCTAssertEqualObjects(response, expectedResponse);
-  };
-
-  [_remoteService emptyCallWithRequest:request
-                               handler:^(GPBEmpty *response, NSError *error) {
-                                 handler(response, error);
-                                 [expectRemote fulfill];
-                               }];
-  [_remoteCronetService emptyCallWithRequest:request
-                                     handler:^(GPBEmpty *response, NSError *error) {
-                                       handler(response, error);
-                                       [expectCronetRemote fulfill];
-                                     }];
-  [_localCleartextService emptyCallWithRequest:request
-                                       handler:^(GPBEmpty *response, NSError *error) {
-                                         handler(response, error);
-                                         [expectCleartext fulfill];
-                                       }];
-  [_localSSLService emptyCallWithRequest:request
-                                 handler:^(GPBEmpty *response, NSError *error) {
-                                   handler(response, error);
-                                   [expectSSL fulfill];
-                                 }];
-
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
-}
-
-- (void)testFullDuplexRPC {
-  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectCronetRemote =
-      [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectCleartext =
-      [self expectationWithDescription:@"Remote RPC finish"];
-  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
-
-  NSArray *requestSizes = @[ @100, @101, @102, @103 ];
-  NSArray *responseSizes = @[ @104, @105, @106, @107 ];
-  XCTAssertEqual([requestSizes count], [responseSizes count]);
-  NSUInteger kRounds = [requestSizes count];
-
-  NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
-  NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
-  for (int i = 0; i < kRounds; i++) {
-    requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
-                                                  requestedResponseSize:responseSizes[i]];
-    responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
-  }
-
-  __block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
-  __block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
-  for (int i = 0; i < 4; i++) {
-    steps[i] = [NSNumber numberWithUnsignedInteger:0];
-    requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
-    [requestsBuffers[i] writeValue:requests[0]];
-  }
-
-  BOOL (^handler)(int, BOOL, RMTStreamingOutputCallResponse *, NSError *) =
-      ^(int index, BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) {
-        XCTAssertNil(error, @"Finished with unexpected error: %@", error);
-        XCTAssertTrue(done || response, @"Event handler called without an event.");
-        if (response) {
-          NSUInteger step = [steps[index] unsignedIntegerValue];
-          XCTAssertLessThan(step, kRounds, @"More than %lu responses received.",
-                            (unsigned long)kRounds);
-          XCTAssertEqualObjects(response, responses[step]);
-          step++;
-          steps[index] = [NSNumber numberWithUnsignedInteger:step];
-          GRXBufferedPipe *pipe = requestsBuffers[index];
-          if (step < kRounds) {
-            [pipe writeValue:requests[step]];
-          } else {
-            [pipe writesFinishedWithError:nil];
-          }
-        }
-        if (done) {
-          NSUInteger step = [steps[index] unsignedIntegerValue];
-          XCTAssertEqual(step, kRounds, @"Received %lu responses instead of %lu.", step, kRounds);
-          return YES;
-        }
-        return NO;
-      };
-
-  [_remoteService
-      fullDuplexCallWithRequestsWriter:requestsBuffers[0]
-                          eventHandler:^(BOOL done,
-                                         RMTStreamingOutputCallResponse *_Nullable response,
-                                         NSError *_Nullable error) {
-                            if (handler(0, done, response, error)) {
-                              [expectRemote fulfill];
-                            }
-                          }];
-  [_remoteCronetService
-      fullDuplexCallWithRequestsWriter:requestsBuffers[1]
-                          eventHandler:^(BOOL done,
-                                         RMTStreamingOutputCallResponse *_Nullable response,
-                                         NSError *_Nullable error) {
-                            if (handler(1, done, response, error)) {
-                              [expectCronetRemote fulfill];
-                            }
-                          }];
-  [_localCleartextService
-      fullDuplexCallWithRequestsWriter:requestsBuffers[2]
-                          eventHandler:^(BOOL done,
-                                         RMTStreamingOutputCallResponse *_Nullable response,
-                                         NSError *_Nullable error) {
-                            if (handler(2, done, response, error)) {
-                              [expectCleartext fulfill];
-                            }
-                          }];
-  [_localSSLService
-      fullDuplexCallWithRequestsWriter:requestsBuffers[3]
-                          eventHandler:^(BOOL done,
-                                         RMTStreamingOutputCallResponse *_Nullable response,
-                                         NSError *_Nullable error) {
-                            if (handler(3, done, response, error)) {
-                              [expectSSL fulfill];
-                            }
-                          }];
-
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
-}
-
-@end
diff --git a/src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist b/src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist
deleted file mode 100644 (file)
index ba72822..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
index 22174b5..3c6ecd5 100644 (file)
@@ -118,6 +118,11 @@ extern const char *kCFStreamVarName;
 
   [GRPCCall resetHostSettings];
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  [GRPCCall closeOpenConnections];
+#pragma clang diagnostic pop
+
   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
   options.transportType = [[self class] transportType];
   options.PEMRootCertificates = [[self class] PEMRootCertificates];
index 34ed668..60d2a98 100644 (file)
@@ -5,46 +5,24 @@ install! 'cocoapods', :deterministic_uuids => false
 # Location of gRPC's repo root relative to this file.
 GRPC_LOCAL_SRC = '../../..'
 
-# Install the dependencies in the main target plus all test targets.
-%w(
-  AllTests
-  RxLibraryUnitTests
-  InteropTestsRemote
-  InteropTestsLocalSSL
-  InteropTestsLocalCleartext
-  InteropTestsRemoteWithCronet
-  InteropTestsMultipleChannels
-  InteropTestsCallOptions
-  UnitTests
-  InteropTestsRemoteCFStream
-  InteropTestsLocalSSLCFStream
-  InteropTestsLocalCleartextCFStream
-  APIv2Tests
-).each do |target_name|
-  target target_name do
-    platform :ios, '8.0'
-    pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
-
-    pod '!ProtoCompiler',            :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
-    pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
+target 'MacTests' do
+  platform :osx, '10.13'
+  pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
 
-    pod 'BoringSSL-GRPC',       :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
+  pod '!ProtoCompiler',            :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
+  pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
 
-    pod 'gRPC',           :path => GRPC_LOCAL_SRC
-    pod 'gRPC-Core',      :path => GRPC_LOCAL_SRC
-    pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
-    pod 'gRPC-ProtoRPC',  :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
-    pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
+  pod 'BoringSSL-GRPC',       :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
 
-    if target_name == 'InteropTestsRemoteWithCronet' or target_name == 'InteropTestsMultipleChannels'
-      pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
-      pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
-    end
-  end
+  pod 'gRPC',           :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core',      :path => GRPC_LOCAL_SRC
+  pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-ProtoRPC',  :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
+  pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
 end
 
-target 'MacTests' do
-  platform :osx, '10.13'
+target 'UnitTests' do 
+  platform :ios, '8.0'
   pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
 
   pod '!ProtoCompiler',            :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
@@ -60,27 +38,30 @@ target 'MacTests' do
 end
 
 %w(
-  CoreCronetEnd2EndTests
-  CronetUnitTests
+  InteropTests
+  CronetTests
 ).each do |target_name|
   target target_name do
     platform :ios, '8.0'
-    pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
-    pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
-    pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
-    pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
+    pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
+
+    pod '!ProtoCompiler',            :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
+    pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
+
+    pod 'BoringSSL-GRPC',       :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
+
+    pod 'gRPC',           :path => GRPC_LOCAL_SRC
+    pod 'gRPC-Core',      :path => GRPC_LOCAL_SRC
+    pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
+    pod 'gRPC-ProtoRPC',  :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
+    pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
+
     pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
-    pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
+    pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
+    pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
   end
 end
 
-target 'ChannelTests' do
-  platform :ios, '8.0'
-  pod 'gRPC', :path => GRPC_LOCAL_SRC
-  pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
-  pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
-end
-
 # gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
 # pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
 # and before they are installed in the user project.
index 27a617c..737d52b 100644 (file)
        objects = {
 
 /* Begin PBXBuildFile section */
-               06467F3A8D01EC493D12ADA2 /* libPods-CronetUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */; };
-               09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */; };
-               0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */; };
-               16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; };
-               1A0FB7F8C95A2F82538BC950 /* libPods-ChannelTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48F1841C9A920626995DC28C /* libPods-ChannelTests.a */; };
-               20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
-               333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
-               5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; };
-               5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5E3B95A521CAC6C500C0A151 /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */; };
-               5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
-               5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */; };
-               5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */; };
-               5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; };
-               5EAD6D291E27047400002378 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5EB2A2E72107DED300EB4B69 /* ChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB2A2E62107DED300EB4B69 /* ChannelTests.m */; };
-               5EB2A2E92107DED300EB4B69 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5EB2A2F82109284500EB4B69 /* InteropTestsMultipleChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */; };
-               5EB2A2FA2109284500EB4B69 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5EB5C3AA21656CEA00ADC300 /* ChannelPoolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */; };
-               5EC5E42B2081782C000EF4AD /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
-               5EC5E42C20817832000EF4AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               5EC5E43B208185A7000EF4AD /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
-               5EC5E43C208185AD000EF4AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               5EC5E43D208185B0000EF4AD /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
-               5EC5E44C208185EC000EF4AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               5EC5E44D208185F0000EF4AD /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
-               5EC5E44E20818948000EF4AD /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
-               5EE84BF41D4717E40050C6CC /* InteropTestsRemoteWithCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */; };
-               5EE84BF61D4717E40050C6CC /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               5EE84BFE1D471D400050C6CC /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */; };
-               6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
-               63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; };
-               635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
-               6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
-               6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
-               6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
-               63DC84181BE15179000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
-               63DC84281BE15267000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
-               63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
-               63DC84391BE15294000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               63DC84481BE152B5000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
-               63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
-               63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
-               63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
-               63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
-               63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
-               6C1A3F81CCF7C998B4813EFD /* libPods-InteropTestsCallOptions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */; };
-               886717A79EFF774F356798E6 /* libPods-InteropTestsMultipleChannels.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */; };
-               91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */; };
+               5E0282E9215AA697007AC99D /* NSErrorUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* NSErrorUnitTests.m */; };
+               5E3F14842278B461007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; };
+               5E3F14852278BF5D007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; };
+               5E3F14862278BFFF007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; };
+               5E3F148D22792856007C6D90 /* ConfigureCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F1487227918AA007C6D90 /* ConfigureCronet.m */; };
+               5E3F148E22792AF5007C6D90 /* ConfigureCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F1487227918AA007C6D90 /* ConfigureCronet.m */; };
+               5E7F486422775B37006656AD /* InteropTestsRemoteWithCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */; };
+               5E7F486522775B41006656AD /* CronetUnitTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.mm */; };
+               5E7F486E22778086006656AD /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F486D22778086006656AD /* CoreCronetEnd2EndTests.mm */; };
+               5E7F487922778226006656AD /* InteropTestsMultipleChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487722778226006656AD /* InteropTestsMultipleChannels.m */; };
+               5E7F487D22778256006656AD /* ChannelPoolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487B22778256006656AD /* ChannelPoolTest.m */; };
+               5E7F487E22778256006656AD /* ChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487C22778256006656AD /* ChannelTests.m */; };
+               5E7F4880227782C1006656AD /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487F227782C1006656AD /* APIv2Tests.m */; };
+               5E7F488322778A88006656AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488222778A88006656AD /* InteropTests.m */; };
+               5E7F488422778A88006656AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488222778A88006656AD /* InteropTests.m */; };
+               5E7F488522778A88006656AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488222778A88006656AD /* InteropTests.m */; };
+               5E7F488722778AEA006656AD /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488622778AEA006656AD /* GRPCClientTests.m */; };
+               5E7F488922778B04006656AD /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488822778B04006656AD /* InteropTestsRemote.m */; };
+               5E7F488B22778B5D006656AD /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */; };
+               5E7F488C22778C60006656AD /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487F227782C1006656AD /* APIv2Tests.m */; };
+               5E7F488D22778C85006656AD /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
+               5E7F488E22778C87006656AD /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
+               5E7F488F22778C8C006656AD /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488822778B04006656AD /* InteropTestsRemote.m */; };
+               5E7F489022778C95006656AD /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */; };
+               5EA4770322736178000F72FC /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
+               5EA477042273617B000F72FC /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
+               5EA4770522736AC4000F72FC /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
+               65EB19E418B39A8374D407BB /* libPods-CronetTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B1511C20E16A8422B58D61A /* libPods-CronetTests.a */; };
+               903163C7FE885838580AEC7A /* libPods-InteropTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D457AD9797664CFA191C3280 /* libPods-InteropTests.a */; };
                953CD2942A3A6D6CE695BE87 /* libPods-MacTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 276873A05AC5479B60DF6079 /* libPods-MacTests.a */; };
-               98478C9F42329DF769A45B6C /* libPods-APIv2Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */; };
                B071230B22669EED004B64A1 /* StressTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B071230A22669EED004B64A1 /* StressTests.m */; };
-               B0BB3F02225E7A3C008DA580 /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
-               B0BB3F03225E7A44008DA580 /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
-               B0BB3F04225E7A8D008DA580 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
-               B0BB3F05225E7A9F008DA580 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
-               B0BB3F06225E7AAD008DA580 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
-               B0BB3F07225E7AB5008DA580 /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */; };
-               B0BB3F08225E7ABA008DA580 /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; };
+               B0BB3F08225E7ABA008DA580 /* NSErrorUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* NSErrorUnitTests.m */; };
                B0BB3F0A225EA511008DA580 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
-               B0BB3F0B225EB110008DA580 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
                B0D39B9A2266F3CB00A4078D /* StressTestsSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = B0D39B992266F3CB00A4078D /* StressTestsSSL.m */; };
                B0D39B9C2266FF9800A4078D /* StressTestsCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = B0D39B9B2266FF9800A4078D /* StressTestsCleartext.m */; };
-               BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; };
-               C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; };
                CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */; };
-               F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXContainerItemProxy section */
-               5E0282EC215AA697007AC99D /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5E7D71B8210B9EC9001EA6BA /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5EAD6D2A1E27047400002378 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5EB2A2EA2107DED300EB4B69 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5EB2A2FB2109284500EB4B69 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               63423F4B1B150A5F006CF63C /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               63DC84191BE15179000708E8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               63DC84291BE15267000708E8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               63DC843A1BE15294000708E8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-               63DC84491BE152B5000708E8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 635697C61B14FC11007A7283;
-                       remoteInfo = Tests;
-               };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
-               635697C51B14FC11007A7283 /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "include/$(PRODUCT_NAME)";
-                       dstSubfolderSpec = 16;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXCopyFilesBuildPhase section */
-
 /* Begin PBXFileReference section */
                02192CF1FF9534E3D18C65FC /* Pods-CronetUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.release.xcconfig"; sourceTree = "<group>"; };
+               070266E2626EB997B54880A3 /* Pods-InteropTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTests/Pods-InteropTests.test.xcconfig"; sourceTree = "<group>"; };
                07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
                0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
                0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartextCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.test.xcconfig"; sourceTree = "<group>"; };
                16A2E4C5839C83FBDA63881F /* Pods-MacTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-MacTests/Pods-MacTests.cronet.xcconfig"; sourceTree = "<group>"; };
                17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = "<group>"; };
+               1B1511C20E16A8422B58D61A /* libPods-CronetTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CronetTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                1E43EAE443CBB4482B1EB071 /* Pods-MacTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-MacTests/Pods-MacTests.release.xcconfig"; sourceTree = "<group>"; };
                1F5E788FBF9A4A06EB9E1ACD /* Pods-MacTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-MacTests/Pods-MacTests.test.xcconfig"; sourceTree = "<group>"; };
                20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+               20F6A3D59D0EE091E2D43953 /* Pods-CronetTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.cronet.xcconfig"; sourceTree = "<group>"; };
                22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                2650FEF00956E7924772F9D9 /* Pods-InteropTestsMultipleChannels.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.release.xcconfig"; sourceTree = "<group>"; };
                276873A05AC5479B60DF6079 /* libPods-MacTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MacTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; sourceTree = "<group>"; };
                573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = "<group>"; };
                5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
+               5AB9A82F289D548D6B8816F9 /* Pods-CronetTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.test.xcconfig"; sourceTree = "<group>"; };
                5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = "<group>"; };
-               5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APIv2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = APIv2Tests.m; sourceTree = "<group>"; };
-               5E3B95A621CAC6C500C0A151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsCallOptions.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsCallOptions.m; sourceTree = "<group>"; };
-               5E7D71B6210B9EC9001EA6BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = "<group>"; };
+               5E0282E8215AA697007AC99D /* NSErrorUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSErrorUnitTests.m; sourceTree = "<group>"; };
+               5E3F14822278B42D007C6D90 /* InteropTestsBlockCallbacks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InteropTestsBlockCallbacks.h; sourceTree = "<group>"; };
+               5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsBlockCallbacks.m; sourceTree = "<group>"; };
+               5E3F1487227918AA007C6D90 /* ConfigureCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ConfigureCronet.m; sourceTree = "<group>"; };
+               5E3F148A227918C4007C6D90 /* ConfigureCronet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConfigureCronet.h; sourceTree = "<group>"; };
+               5E7F485922775B15006656AD /* CronetTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               5E7F486622776AD8006656AD /* Cronet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cronet.framework; path = Pods/CronetFramework/Cronet.framework; sourceTree = "<group>"; };
+               5E7F486D22778086006656AD /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = "<group>"; };
+               5E7F487722778226006656AD /* InteropTestsMultipleChannels.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsMultipleChannels.m; sourceTree = "<group>"; };
+               5E7F487B22778256006656AD /* ChannelPoolTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChannelPoolTest.m; sourceTree = "<group>"; };
+               5E7F487C22778256006656AD /* ChannelTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChannelTests.m; sourceTree = "<group>"; };
+               5E7F487F227782C1006656AD /* APIv2Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APIv2Tests.m; sourceTree = "<group>"; };
+               5E7F488122778A88006656AD /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
+               5E7F488222778A88006656AD /* InteropTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTests.m; sourceTree = "<group>"; };
+               5E7F488622778AEA006656AD /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = "<group>"; };
+               5E7F488822778B04006656AD /* InteropTestsRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemote.m; sourceTree = "<group>"; };
+               5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
+               5EA476F42272816A000F72FC /* InteropTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; sourceTree = "<group>"; };
-               5EAD6D241E27047400002378 /* CronetUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = "<group>"; };
-               5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               5EAD6D261E27047400002378 /* CronetUnitTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CronetUnitTests.mm; path = CronetTests/CronetUnitTests.mm; sourceTree = SOURCE_ROOT; };
                5EAFE8271F8EFB87007F2189 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
-               5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChannelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EB2A2E62107DED300EB4B69 /* ChannelTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChannelTests.m; sourceTree = "<group>"; };
-               5EB2A2E82107DED300EB4B69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsMultipleChannels.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsMultipleChannels.m; sourceTree = "<group>"; };
-               5EB2A2F92109284500EB4B69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChannelPoolTest.m; sourceTree = "<group>"; };
-               5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalCleartextCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalSSLCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteWithCronet.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemoteWithCronet.m; sourceTree = "<group>"; };
-               5EE84BF51D4717E40050C6CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = "<group>"; };
-               63423F441B150A5F006CF63C /* AllTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AllTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               63423F501B151B77006CF63C /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
-               635697C71B14FC11007A7283 /* libTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTests.a; sourceTree = BUILT_PRODUCTS_DIR; };
-               635697CC1B14FC11007A7283 /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
+               5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = InteropTestsRemoteWithCronet.m; path = CronetTests/InteropTestsRemoteWithCronet.m; sourceTree = SOURCE_ROOT; };
                635697D81B14FC11007A7283 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTests.m; sourceTree = "<group>"; };
-               63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalCleartext.m; sourceTree = "<group>"; };
-               6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemote.m; sourceTree = "<group>"; };
-               63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxLibraryUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemote.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalSSL.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalCleartext.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
-               63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = "<group>"; };
+               63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InteropTestsLocalCleartext.m; path = InteropTests/InteropTestsLocalCleartext.m; sourceTree = SOURCE_ROOT; };
+               63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InteropTestsLocalSSL.m; path = InteropTests/InteropTestsLocalSSL.m; sourceTree = SOURCE_ROOT; };
                63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = "<group>"; };
                64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
                6793C9D019CB268C5BB491A2 /* Pods-CoreCronetEnd2EndTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.test.xcconfig"; sourceTree = "<group>"; };
+               680439AC2BC8761EDD54A1EA /* Pods-InteropTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTests/Pods-InteropTests.debug.xcconfig"; sourceTree = "<group>"; };
                73D2DF07027835BA0FB0B1C0 /* Pods-InteropTestsCallOptions.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.cronet.xcconfig"; sourceTree = "<group>"; };
                781089FAE980F51F88A3BE0B /* Pods-RxLibraryUnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.test.xcconfig"; sourceTree = "<group>"; };
                79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.cronet.xcconfig"; sourceTree = "<group>"; };
                7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = "<group>"; };
                7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; sourceTree = "<group>"; };
+               7F4F42EBAF311E9F84FCA32E /* Pods-CronetTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.release.xcconfig"; sourceTree = "<group>"; };
                8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; sourceTree = "<group>"; };
                8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIv2Tests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests.cronet.xcconfig"; sourceTree = "<group>"; };
                90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.cronet.xcconfig"; sourceTree = "<group>"; };
                C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CronetUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                C9172F9020E8C97A470D7250 /* Pods-InteropTestsCallOptions.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.release.xcconfig"; sourceTree = "<group>"; };
                CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AllTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+               CDF6CC70B8BF9D10EFE7D199 /* Pods-InteropTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTests/Pods-InteropTests.cronet.xcconfig"; sourceTree = "<group>"; };
                D13BEC8181B8E678A1B52F54 /* Pods-InteropTestsLocalSSL.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.test.xcconfig"; sourceTree = "<group>"; };
+               D457AD9797664CFA191C3280 /* libPods-InteropTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                D52B92A7108602F170DA8091 /* Pods-ChannelTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.release.xcconfig"; sourceTree = "<group>"; };
                DB1F4391AF69D20D38D74B67 /* Pods-AllTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.test.xcconfig"; sourceTree = "<group>"; };
                DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemote.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.cronet.xcconfig"; sourceTree = "<group>"; };
                EA8B122ACDE73E3AAA0E4A19 /* Pods-InteropTestsMultipleChannels.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.test.xcconfig"; sourceTree = "<group>"; };
                EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = "<group>"; };
+               EC66920112123D2DB1CB7F6C /* Pods-CronetTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.debug.xcconfig"; sourceTree = "<group>"; };
                F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSLCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+               F6A7EECACBB4849DDD3F450A /* Pods-InteropTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTests/Pods-InteropTests.release.xcconfig"; sourceTree = "<group>"; };
                F9E48EF5ACB1F38825171C5F /* Pods-ChannelTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.debug.xcconfig"; sourceTree = "<group>"; };
                FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartext.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               5E0282EB215AA697007AC99D /* libTests.a in Frameworks */,
                                CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               5E3B959F21CAC6C500C0A151 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               98478C9F42329DF769A45B6C /* libPods-APIv2Tests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E7D71AF210B9EC8001EA6BA /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */,
-                               6C1A3F81CCF7C998B4813EFD /* libPods-InteropTestsCallOptions.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */,
-                               60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EAD6D211E27047400002378 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EAD6D291E27047400002378 /* libTests.a in Frameworks */,
-                               06467F3A8D01EC493D12ADA2 /* libPods-CronetUnitTests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2E12107DED300EB4B69 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EB2A2E92107DED300EB4B69 /* libTests.a in Frameworks */,
-                               1A0FB7F8C95A2F82538BC950 /* libPods-ChannelTests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2F22109284500EB4B69 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EB2A2FA2109284500EB4B69 /* libTests.a in Frameworks */,
-                               886717A79EFF774F356798E6 /* libPods-InteropTestsMultipleChannels.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E41E208177CC000EF4AD /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E42E2081856B000EF4AD /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E43F208185CE000EF4AD /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EE84BEE1D4717E40050C6CC /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EE84BF61D4717E40050C6CC /* libTests.a in Frameworks */,
-                               09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63423F411B150A5F006CF63C /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */,
-                               F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               635697C41B14FC11007A7283 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84101BE15179000708E8 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC84181BE15179000708E8 /* libTests.a in Frameworks */,
-                               20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84201BE15267000708E8 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC84281BE15267000708E8 /* libTests.a in Frameworks */,
-                               0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84311BE15294000708E8 /* Frameworks */ = {
+               5E7F485622775B15006656AD /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               63DC84391BE15294000708E8 /* libTests.a in Frameworks */,
-                               16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */,
+                               65EB19E418B39A8374D407BB /* libPods-CronetTests.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               63DC84401BE152B5000708E8 /* Frameworks */ = {
+               5EA476F12272816A000F72FC /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               63DC84481BE152B5000708E8 /* libTests.a in Frameworks */,
-                               333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */,
+                               903163C7FE885838580AEC7A /* libPods-InteropTests.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                136D535E19727099B941D7B1 /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               5E7F486622776AD8006656AD /* Cronet.framework */,
                                35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */,
                                CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */,
                                FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */,
                                22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */,
                                B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */,
                                276873A05AC5479B60DF6079 /* libPods-MacTests.a */,
+                               D457AD9797664CFA191C3280 /* libPods-InteropTests.a */,
+                               1B1511C20E16A8422B58D61A /* libPods-CronetTests.a */,
                        );
                        name = Frameworks;
                        sourceTree = "<group>";
                                1F5E788FBF9A4A06EB9E1ACD /* Pods-MacTests.test.xcconfig */,
                                16A2E4C5839C83FBDA63881F /* Pods-MacTests.cronet.xcconfig */,
                                1E43EAE443CBB4482B1EB071 /* Pods-MacTests.release.xcconfig */,
+                               680439AC2BC8761EDD54A1EA /* Pods-InteropTests.debug.xcconfig */,
+                               070266E2626EB997B54880A3 /* Pods-InteropTests.test.xcconfig */,
+                               CDF6CC70B8BF9D10EFE7D199 /* Pods-InteropTests.cronet.xcconfig */,
+                               F6A7EECACBB4849DDD3F450A /* Pods-InteropTests.release.xcconfig */,
+                               EC66920112123D2DB1CB7F6C /* Pods-CronetTests.debug.xcconfig */,
+                               5AB9A82F289D548D6B8816F9 /* Pods-CronetTests.test.xcconfig */,
+                               20F6A3D59D0EE091E2D43953 /* Pods-CronetTests.cronet.xcconfig */,
+                               7F4F42EBAF311E9F84FCA32E /* Pods-CronetTests.release.xcconfig */,
                        );
                        name = Pods;
                        sourceTree = "<group>";
                5E0282E7215AA697007AC99D /* UnitTests */ = {
                        isa = PBXGroup;
                        children = (
-                               5E0282E8215AA697007AC99D /* UnitTests.m */,
-                               5E0282EA215AA697007AC99D /* Info.plist */,
+                               5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */,
+                               5E7F488622778AEA006656AD /* GRPCClientTests.m */,
+                               5E7F487F227782C1006656AD /* APIv2Tests.m */,
+                               5E7F487B22778256006656AD /* ChannelPoolTest.m */,
+                               5E7F487C22778256006656AD /* ChannelTests.m */,
+                               5E0282E8215AA697007AC99D /* NSErrorUnitTests.m */,
                        );
                        path = UnitTests;
                        sourceTree = "<group>";
                };
-               5E3B95A321CAC6C500C0A151 /* APIv2Tests */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */,
-                               5E3B95A621CAC6C500C0A151 /* Info.plist */,
-                       );
-                       path = APIv2Tests;
-                       sourceTree = "<group>";
-               };
-               5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */,
-                               5E7D71B6210B9EC9001EA6BA /* Info.plist */,
-                       );
-                       path = InteropTestsCallOptions;
-                       sourceTree = "<group>";
-               };
-               5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */,
-                       );
-                       path = CoreCronetEnd2EndTests;
-                       sourceTree = "<group>";
-               };
-               5EAD6D251E27047400002378 /* CronetUnitTests */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5EAD6D261E27047400002378 /* CronetUnitTests.m */,
-                               5EAD6D281E27047400002378 /* Info.plist */,
-                       );
-                       path = CronetUnitTests;
-                       sourceTree = "<group>";
-               };
-               5EB2A2E52107DED300EB4B69 /* ChannelTests */ = {
-                       isa = PBXGroup;
-                       children = (
-                               5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */,
-                               5EB2A2E62107DED300EB4B69 /* ChannelTests.m */,
-                               5EB2A2E82107DED300EB4B69 /* Info.plist */,
-                       );
-                       path = ChannelTests;
-                       sourceTree = "<group>";
-               };
-               5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */ = {
+               5E7F485A22775B15006656AD /* CronetTests */ = {
                        isa = PBXGroup;
                        children = (
-                               5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */,
-                               5EB2A2F92109284500EB4B69 /* Info.plist */,
+                               5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */,
+                               5E7F486D22778086006656AD /* CoreCronetEnd2EndTests.mm */,
+                               5EAD6D261E27047400002378 /* CronetUnitTests.mm */,
                        );
-                       path = InteropTestsMultipleChannels;
+                       path = CronetTests;
                        sourceTree = "<group>";
                };
-               5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
+               5E7F48762277820F006656AD /* InteropTests */ = {
                        isa = PBXGroup;
                        children = (
-                               5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */,
-                               5EE84BF51D4717E40050C6CC /* Info.plist */,
+                               5E7F488822778B04006656AD /* InteropTestsRemote.m */,
+                               5E7F488122778A88006656AD /* InteropTests.h */,
+                               5E7F488222778A88006656AD /* InteropTests.m */,
+                               63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */,
+                               63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */,
+                               5E7F487722778226006656AD /* InteropTestsMultipleChannels.m */,
+                               5E3F14822278B42D007C6D90 /* InteropTestsBlockCallbacks.h */,
+                               5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */,
                        );
-                       path = InteropTestsRemoteWithCronet;
+                       path = InteropTests;
                        sourceTree = "<group>";
                };
                635697BE1B14FC11007A7283 = {
                        isa = PBXGroup;
                        children = (
+                               5E7F48762277820F006656AD /* InteropTests */,
                                635697C91B14FC11007A7283 /* Tests */,
                                63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */,
-                               5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
-                               5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
-                               5EAD6D251E27047400002378 /* CronetUnitTests */,
-                               5EB2A2E52107DED300EB4B69 /* ChannelTests */,
-                               5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */,
-                               5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */,
                                5E0282E7215AA697007AC99D /* UnitTests */,
-                               5E3B95A321CAC6C500C0A151 /* APIv2Tests */,
                                B0BB3EF8225E795F008DA580 /* MacTests */,
+                               5E7F485A22775B15006656AD /* CronetTests */,
                                635697C81B14FC11007A7283 /* Products */,
                                51E4650F34F854F41FF053B3 /* Pods */,
                                136D535E19727099B941D7B1 /* Frameworks */,
                635697C81B14FC11007A7283 /* Products */ = {
                        isa = PBXGroup;
                        children = (
-                               635697C71B14FC11007A7283 /* libTests.a */,
-                               63423F441B150A5F006CF63C /* AllTests.xctest */,
-                               63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */,
-                               63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */,
-                               63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */,
-                               63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */,
-                               5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */,
-                               5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */,
-                               5EAD6D241E27047400002378 /* CronetUnitTests.xctest */,
-                               5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */,
-                               5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */,
-                               5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */,
-                               5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */,
-                               5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */,
-                               5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */,
                                5E0282E6215AA697007AC99D /* UnitTests.xctest */,
-                               5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */,
                                B0BB3EF7225E795F008DA580 /* MacTests.xctest */,
+                               5EA476F42272816A000F72FC /* InteropTests.xctest */,
+                               5E7F485922775B15006656AD /* CronetTests.xctest */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                635697C91B14FC11007A7283 /* Tests */ = {
                        isa = PBXGroup;
                        children = (
+                               5E3F148A227918C4007C6D90 /* ConfigureCronet.h */,
+                               5E3F1487227918AA007C6D90 /* ConfigureCronet.m */,
                                5EAFE8271F8EFB87007F2189 /* version.h */,
-                               6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */,
-                               63E240CC1B6C4D3A005F3B0E /* InteropTests.h */,
-                               635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */,
-                               6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */,
-                               63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */,
-                               63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */,
-                               63423F501B151B77006CF63C /* RxLibraryUnitTests.m */,
-                               635697CC1B14FC11007A7283 /* Tests.m */,
                                635697D71B14FC11007A7283 /* Supporting Files */,
                        );
                        name = Tests;
                        buildRules = (
                        );
                        dependencies = (
-                               5E0282ED215AA697007AC99D /* PBXTargetDependency */,
                        );
                        name = UnitTests;
                        productName = UnitTests;
                        productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               5E3B95A121CAC6C500C0A151 /* APIv2Tests */ = {
+               5E7F485822775B15006656AD /* CronetTests */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 5E3B95A721CAC6C500C0A151 /* Build configuration list for PBXNativeTarget "APIv2Tests" */;
+                       buildConfigurationList = 5E7F485E22775B15006656AD /* Build configuration list for PBXNativeTarget "CronetTests" */;
                        buildPhases = (
-                               EDDD3FA856BCA3443ED36D1E /* [CP] Check Pods Manifest.lock */,
-                               5E3B959E21CAC6C500C0A151 /* Sources */,
-                               5E3B959F21CAC6C500C0A151 /* Frameworks */,
-                               5E3B95A021CAC6C500C0A151 /* Resources */,
-                               C17B826BBD02FDD4A5F355AF /* [CP] Copy Pods Resources */,
+                               CCAEC0F23E05489651A07D53 /* [CP] Check Pods Manifest.lock */,
+                               5E7F485522775B15006656AD /* Sources */,
+                               5E7F485622775B15006656AD /* Frameworks */,
+                               5E7F485722775B15006656AD /* Resources */,
+                               292EA42A76AC7933A37235FD /* [CP] Embed Pods Frameworks */,
+                               30AFD6F6FC40B9923632A866 /* [CP] Copy Pods Resources */,
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
-                       name = APIv2Tests;
-                       productName = APIv2Tests;
-                       productReference = 5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */;
+                       name = CronetTests;
+                       productName = CronetTests;
+                       productReference = 5E7F485922775B15006656AD /* CronetTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */ = {
+               5EA476F32272816A000F72FC /* InteropTests */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */;
+                       buildConfigurationList = 5EA477002272816B000F72FC /* Build configuration list for PBXNativeTarget "InteropTests" */;
                        buildPhases = (
-                               2865C6386D677998F861E183 /* [CP] Check Pods Manifest.lock */,
-                               5E7D71AE210B9EC8001EA6BA /* Sources */,
-                               5E7D71AF210B9EC8001EA6BA /* Frameworks */,
-                               5E7D71B0210B9EC8001EA6BA /* Resources */,
-                               6BA6D00B1816306453BF82D4 /* [CP] Copy Pods Resources */,
+                               40BCDB09674DF988C708D22B /* [CP] Check Pods Manifest.lock */,
+                               5EA476F02272816A000F72FC /* Sources */,
+                               5EA476F12272816A000F72FC /* Frameworks */,
+                               5EA476F22272816A000F72FC /* Resources */,
+                               D11CB94CF56A1E53760D29D8 /* [CP] Copy Pods Resources */,
+                               0FEFD5FC6B323AC95549AE4A /* [CP] Embed Pods Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               5E7D71B9210B9EC9001EA6BA /* PBXTargetDependency */,
                        );
-                       name = InteropTestsCallOptions;
-                       productName = InteropTestsCallOptions;
-                       productReference = 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */;
+                       name = InteropTests;
+                       productName = InteropTests;
+                       productReference = 5EA476F42272816A000F72FC /* InteropTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
+               B0BB3EF6225E795F008DA580 /* MacTests */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */;
+                       buildConfigurationList = B0BB3EFC225E795F008DA580 /* Build configuration list for PBXNativeTarget "MacTests" */;
                        buildPhases = (
-                               F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */,
-                               5E8A5DA01D3840B4000F8BC4 /* Sources */,
-                               5E8A5DA11D3840B4000F8BC4 /* Frameworks */,
-                               5E8A5DA21D3840B4000F8BC4 /* Resources */,
-                               E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */,
+                               E5B20F69559C6AE299DFEA7C /* [CP] Check Pods Manifest.lock */,
+                               B0BB3EF3225E795F008DA580 /* Sources */,
+                               B0BB3EF4225E795F008DA580 /* Frameworks */,
+                               B0BB3EF5225E795F008DA580 /* Resources */,
+                               452FDC3918FEC23ECAFD31EC /* [CP] Copy Pods Resources */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */,
                        );
-                       name = CoreCronetEnd2EndTests;
-                       productName = CoreCronetEnd2EndTests;
-                       productReference = 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */;
+                       name = MacTests;
+                       productName = MacTests;
+                       productReference = B0BB3EF7225E795F008DA580 /* MacTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               5EAD6D231E27047400002378 /* CronetUnitTests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EAD6D2F1E27047400002378 /* Build configuration list for PBXNativeTarget "CronetUnitTests" */;
-                       buildPhases = (
-                               80E2DDD2EC04A4009F45E933 /* [CP] Check Pods Manifest.lock */,
-                               5EAD6D201E27047400002378 /* Sources */,
-                               5EAD6D211E27047400002378 /* Frameworks */,
-                               5EAD6D221E27047400002378 /* Resources */,
-                               A686B9967BB4CB81B1CBF8F8 /* [CP] Embed Pods Frameworks */,
-                       );
-                       buildRules = (
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               635697BF1B14FC11007A7283 /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0630;
+                               ORGANIZATIONNAME = gRPC;
+                               TargetAttributes = {
+                                       5E0282E5215AA697007AC99D = {
+                                               CreatedOnToolsVersion = 9.2;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       5E7F485822775B15006656AD = {
+                                               CreatedOnToolsVersion = 10.1;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       5EA476F32272816A000F72FC = {
+                                               CreatedOnToolsVersion = 10.1;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       B0BB3EF6225E795F008DA580 = {
+                                               CreatedOnToolsVersion = 10.1;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                               };
+                       };
+                       buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */;
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               English,
+                               en,
                        );
-                       dependencies = (
-                               5EAD6D2B1E27047400002378 /* PBXTargetDependency */,
+                       mainGroup = 635697BE1B14FC11007A7283;
+                       productRefGroup = 635697C81B14FC11007A7283 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               5E0282E5215AA697007AC99D /* UnitTests */,
+                               B0BB3EF6225E795F008DA580 /* MacTests */,
+                               5EA476F32272816A000F72FC /* InteropTests */,
+                               5E7F485822775B15006656AD /* CronetTests */,
                        );
-                       name = CronetUnitTests;
-                       productName = CronetUnitTests;
-                       productReference = 5EAD6D241E27047400002378 /* CronetUnitTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
                };
-               5EB2A2E32107DED300EB4B69 /* ChannelTests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EB2A2F02107DED300EB4B69 /* Build configuration list for PBXNativeTarget "ChannelTests" */;
-                       buildPhases = (
-                               021B3B1F545989843EBC9A4B /* [CP] Check Pods Manifest.lock */,
-                               5EB2A2E02107DED300EB4B69 /* Sources */,
-                               5EB2A2E12107DED300EB4B69 /* Frameworks */,
-                               5EB2A2E22107DED300EB4B69 /* Resources */,
-                               1EAF0CBDBFAB18D4DA64535D /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               5EB2A2EB2107DED300EB4B69 /* PBXTargetDependency */,
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               5E0282E4215AA697007AC99D /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       name = ChannelTests;
-                       productName = ChannelTests;
-                       productReference = 5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
                };
-               5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EB2A3012109284500EB4B69 /* Build configuration list for PBXNativeTarget "InteropTestsMultipleChannels" */;
-                       buildPhases = (
-                               8C1ED025E07C4D457C355336 /* [CP] Check Pods Manifest.lock */,
-                               5EB2A2F12109284500EB4B69 /* Sources */,
-                               5EB2A2F22109284500EB4B69 /* Frameworks */,
-                               5EB2A2F32109284500EB4B69 /* Resources */,
-                               8D685CB612835DB3F7A6F14A /* [CP] Embed Pods Frameworks */,
-                               0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */,
+               5E7F485722775B15006656AD /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               5EA476F22272816A000F72FC /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5EA4770522736AC4000F72FC /* TestCertificates.bundle in Resources */,
                        );
-                       dependencies = (
-                               5EB2A2FC2109284500EB4B69 /* PBXTargetDependency */,
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               B0BB3EF5225E795F008DA580 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               B0BB3F0A225EA511008DA580 /* TestCertificates.bundle in Resources */,
                        );
-                       name = InteropTestsMultipleChannels;
-                       productName = InteropTestsMultipleChannels;
-                       productReference = 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
                };
-               5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EC5E42A208177CD000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsRemoteCFStream" */;
-                       buildPhases = (
-                               483CDBBAEAEFCB530ADDDDD5 /* [CP] Check Pods Manifest.lock */,
-                               5EC5E41D208177CC000EF4AD /* Sources */,
-                               5EC5E41E208177CC000EF4AD /* Frameworks */,
-                               5EC5E41F208177CC000EF4AD /* Resources */,
-                               95FBC48B743503845678584F /* [CP] Copy Pods Resources */,
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               0FEFD5FC6B323AC95549AE4A /* [CP] Embed Pods Frameworks */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-frameworks.sh",
+                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
                        );
-                       dependencies = (
+                       name = "[CP] Embed Pods Frameworks";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
                        );
-                       name = InteropTestsRemoteCFStream;
-                       productName = InteropTestsRemoteCFStream;
-                       productReference = 5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-frameworks.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               5EC5E4302081856B000EF4AD /* InteropTestsLocalCleartextCFStream */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EC5E4362081856C000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartextCFStream" */;
-                       buildPhases = (
-                               252A376345E38FD452A89C3D /* [CP] Check Pods Manifest.lock */,
-                               5EC5E42D2081856B000EF4AD /* Sources */,
-                               5EC5E42E2081856B000EF4AD /* Frameworks */,
-                               5EC5E42F2081856B000EF4AD /* Resources */,
-                               A023FB55205A7EA37D413549 /* [CP] Copy Pods Resources */,
+               292EA42A76AC7933A37235FD /* [CP] Embed Pods Frameworks */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-CronetTests/Pods-CronetTests-frameworks.sh",
+                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
                        );
-                       dependencies = (
+                       name = "[CP] Embed Pods Frameworks";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
                        );
-                       name = InteropTestsLocalCleartextCFStream;
-                       productName = InteropTestsLocalCleartextCFStream;
-                       productReference = 5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
-               5EC5E441208185CE000EF4AD /* InteropTestsLocalSSLCFStream */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EC5E447208185CE000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSLCFStream" */;
-                       buildPhases = (
-                               F3D5B2CDA172580341682830 /* [CP] Check Pods Manifest.lock */,
-                               5EC5E43E208185CE000EF4AD /* Sources */,
-                               5EC5E43F208185CE000EF4AD /* Frameworks */,
-                               5EC5E440208185CE000EF4AD /* Resources */,
-                               4EB2FFF40BB00AD0C545D7EF /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = InteropTestsLocalSSLCFStream;
-                       productName = InteropTestsLocalSSLCFStream;
-                       productReference = 5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
-               5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */;
-                       buildPhases = (
-                               C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */,
-                               5EE84BED1D4717E40050C6CC /* Sources */,
-                               5EE84BEE1D4717E40050C6CC /* Frameworks */,
-                               5EE84BEF1D4717E40050C6CC /* Resources */,
-                               31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */,
-                               DB4D0E73C229F2FF3B364AB3 /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               5EE84BF81D4717E40050C6CC /* PBXTargetDependency */,
-                       );
-                       name = InteropTestsRemoteWithCronet;
-                       productName = InteropTestsRemoteWithCronet;
-                       productReference = 5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
-               63423F431B150A5F006CF63C /* AllTests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */;
-                       buildPhases = (
-                               914ADDD7106BA9BB8A7E569F /* [CP] Check Pods Manifest.lock */,
-                               63423F401B150A5F006CF63C /* Sources */,
-                               63423F411B150A5F006CF63C /* Frameworks */,
-                               63423F421B150A5F006CF63C /* Resources */,
-                               A441F71824DCB9D0CA297748 /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               63423F4C1B150A5F006CF63C /* PBXTargetDependency */,
-                       );
-                       name = AllTests;
-                       productName = AllTests;
-                       productReference = 63423F441B150A5F006CF63C /* AllTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CronetTests/Pods-CronetTests-frameworks.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               635697C61B14FC11007A7283 /* Tests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 635697DB1B14FC11007A7283 /* Build configuration list for PBXNativeTarget "Tests" */;
-                       buildPhases = (
-                               635697C31B14FC11007A7283 /* Sources */,
-                               635697C41B14FC11007A7283 /* Frameworks */,
-                               635697C51B14FC11007A7283 /* CopyFiles */,
+               30AFD6F6FC40B9923632A866 /* [CP] Copy Pods Resources */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-CronetTests/Pods-CronetTests-resources.sh",
+                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle",
                        );
-                       dependencies = (
+                       name = "[CP] Copy Pods Resources";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
                        );
-                       name = Tests;
-                       productName = Tests;
-                       productReference = 635697C71B14FC11007A7283 /* libTests.a */;
-                       productType = "com.apple.product-type.library.static";
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CronetTests/Pods-CronetTests-resources.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               63DC84121BE15179000708E8 /* RxLibraryUnitTests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 63DC841B1BE15179000708E8 /* Build configuration list for PBXNativeTarget "RxLibraryUnitTests" */;
-                       buildPhases = (
-                               B2986CEEE8CDD4901C97598B /* [CP] Check Pods Manifest.lock */,
-                               63DC840F1BE15179000708E8 /* Sources */,
-                               63DC84101BE15179000708E8 /* Frameworks */,
-                               63DC84111BE15179000708E8 /* Resources */,
-                               C977426A8727267BBAC7D48E /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
+               40BCDB09674DF988C708D22B /* [CP] Check Pods Manifest.lock */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       dependencies = (
-                               63DC841A1BE15179000708E8 /* PBXTargetDependency */,
+                       inputFileListPaths = (
                        );
-                       name = RxLibraryUnitTests;
-                       productName = RxLibraryUnitTests;
-                       productReference = 63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
-               63DC84221BE15267000708E8 /* InteropTestsRemote */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 63DC842B1BE15267000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsRemote" */;
-                       buildPhases = (
-                               4C406327D3907A5E5FBA8AC9 /* [CP] Check Pods Manifest.lock */,
-                               63DC841F1BE15267000708E8 /* Sources */,
-                               63DC84201BE15267000708E8 /* Frameworks */,
-                               63DC84211BE15267000708E8 /* Resources */,
-                               C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */,
+                       inputPaths = (
+                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+                               "${PODS_ROOT}/Manifest.lock",
                        );
-                       buildRules = (
+                       name = "[CP] Check Pods Manifest.lock";
+                       outputFileListPaths = (
                        );
-                       dependencies = (
-                               63DC842A1BE15267000708E8 /* PBXTargetDependency */,
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/Pods-InteropTests-checkManifestLockResult.txt",
                        );
-                       name = InteropTestsRemote;
-                       productName = InteropTests;
-                       productReference = 63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       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;
                };
-               63DC84331BE15294000708E8 /* InteropTestsLocalSSL */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 63DC843C1BE15294000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSL" */;
-                       buildPhases = (
-                               5C20DCCB71C3991E6FE78C22 /* [CP] Check Pods Manifest.lock */,
-                               63DC84301BE15294000708E8 /* Sources */,
-                               63DC84311BE15294000708E8 /* Frameworks */,
-                               63DC84321BE15294000708E8 /* Resources */,
-                               693DD0B453431D64EA24FD66 /* [CP] Copy Pods Resources */,
+               452FDC3918FEC23ECAFD31EC /* [CP] Copy Pods Resources */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-MacTests/Pods-MacTests-resources.sh",
+                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-macOS/gRPCCertificates.bundle",
                        );
-                       dependencies = (
-                               63DC843B1BE15294000708E8 /* PBXTargetDependency */,
+                       name = "[CP] Copy Pods Resources";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
                        );
-                       name = InteropTestsLocalSSL;
-                       productName = InteropTestsLocalSSL;
-                       productReference = 63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MacTests/Pods-MacTests-resources.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 63DC844B1BE152B5000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartext" */;
-                       buildPhases = (
-                               7418AC7B3844B29E48D24FC7 /* [CP] Check Pods Manifest.lock */,
-                               63DC843F1BE152B5000708E8 /* Sources */,
-                               63DC84401BE152B5000708E8 /* Frameworks */,
-                               63DC84411BE152B5000708E8 /* Resources */,
-                               8AD3130D3C58A0FB32FF2A36 /* [CP] Copy Pods Resources */,
+               9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       buildRules = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh",
+                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle",
                        );
-                       dependencies = (
-                               63DC844A1BE152B5000708E8 /* PBXTargetDependency */,
+                       name = "[CP] Copy Pods Resources";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
                        );
-                       name = InteropTestsLocalCleartext;
-                       productName = InteropTestsLocalCleartext;
-                       productReference = 63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               B0BB3EF6225E795F008DA580 /* MacTests */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = B0BB3EFC225E795F008DA580 /* Build configuration list for PBXNativeTarget "MacTests" */;
-                       buildPhases = (
-                               E5B20F69559C6AE299DFEA7C /* [CP] Check Pods Manifest.lock */,
-                               B0BB3EF3225E795F008DA580 /* Sources */,
-                               B0BB3EF4225E795F008DA580 /* Frameworks */,
-                               B0BB3EF5225E795F008DA580 /* Resources */,
-                               452FDC3918FEC23ECAFD31EC /* [CP] Copy Pods Resources */,
-                       );
-                       buildRules = (
+               CCAEC0F23E05489651A07D53 /* [CP] Check Pods Manifest.lock */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
                        );
-                       dependencies = (
+                       inputFileListPaths = (
                        );
-                       name = MacTests;
-                       productName = MacTests;
-                       productReference = B0BB3EF7225E795F008DA580 /* MacTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-               635697BF1B14FC11007A7283 /* Project object */ = {
-                       isa = PBXProject;
-                       attributes = {
-                               LastUpgradeCheck = 0630;
-                               ORGANIZATIONNAME = gRPC;
-                               TargetAttributes = {
-                                       5E0282E5215AA697007AC99D = {
-                                               CreatedOnToolsVersion = 9.2;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5E3B95A121CAC6C500C0A151 = {
-                                               CreatedOnToolsVersion = 10.0;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5E7D71B1210B9EC8001EA6BA = {
-                                               CreatedOnToolsVersion = 9.3;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5E8A5DA31D3840B4000F8BC4 = {
-                                               CreatedOnToolsVersion = 7.3.1;
-                                       };
-                                       5EAD6D231E27047400002378 = {
-                                               CreatedOnToolsVersion = 7.3.1;
-                                       };
-                                       5EB2A2E32107DED300EB4B69 = {
-                                               CreatedOnToolsVersion = 9.3;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5EB2A2F42109284500EB4B69 = {
-                                               CreatedOnToolsVersion = 9.3;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5EC5E420208177CC000EF4AD = {
-                                               CreatedOnToolsVersion = 9.2;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5EC5E4302081856B000EF4AD = {
-                                               CreatedOnToolsVersion = 9.2;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5EC5E441208185CE000EF4AD = {
-                                               CreatedOnToolsVersion = 9.2;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                                       5EE84BF01D4717E40050C6CC = {
-                                               CreatedOnToolsVersion = 7.3.1;
-                                       };
-                                       63423F431B150A5F006CF63C = {
-                                               CreatedOnToolsVersion = 6.3.1;
-                                       };
-                                       635697C61B14FC11007A7283 = {
-                                               CreatedOnToolsVersion = 6.3.1;
-                                       };
-                                       63DC84121BE15179000708E8 = {
-                                               CreatedOnToolsVersion = 7.0.1;
-                                       };
-                                       63DC84221BE15267000708E8 = {
-                                               CreatedOnToolsVersion = 7.0.1;
-                                       };
-                                       63DC84331BE15294000708E8 = {
-                                               CreatedOnToolsVersion = 7.0.1;
-                                       };
-                                       63DC84421BE152B5000708E8 = {
-                                               CreatedOnToolsVersion = 7.0.1;
-                                       };
-                                       B0BB3EF6225E795F008DA580 = {
-                                               CreatedOnToolsVersion = 10.1;
-                                               ProvisioningStyle = Automatic;
-                                       };
-                               };
-                       };
-                       buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */;
-                       compatibilityVersion = "Xcode 3.2";
-                       developmentRegion = English;
-                       hasScannedForEncodings = 0;
-                       knownRegions = (
-                               en,
+                       inputPaths = (
+                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+                               "${PODS_ROOT}/Manifest.lock",
                        );
-                       mainGroup = 635697BE1B14FC11007A7283;
-                       productRefGroup = 635697C81B14FC11007A7283 /* Products */;
-                       projectDirPath = "";
-                       projectRoot = "";
-                       targets = (
-                               635697C61B14FC11007A7283 /* Tests */,
-                               63423F431B150A5F006CF63C /* AllTests */,
-                               63DC84121BE15179000708E8 /* RxLibraryUnitTests */,
-                               63DC84221BE15267000708E8 /* InteropTestsRemote */,
-                               63DC84331BE15294000708E8 /* InteropTestsLocalSSL */,
-                               63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */,
-                               5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
-                               5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
-                               5EAD6D231E27047400002378 /* CronetUnitTests */,
-                               5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */,
-                               5EC5E4302081856B000EF4AD /* InteropTestsLocalCleartextCFStream */,
-                               5EC5E441208185CE000EF4AD /* InteropTestsLocalSSLCFStream */,
-                               5EB2A2E32107DED300EB4B69 /* ChannelTests */,
-                               5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */,
-                               5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */,
-                               5E0282E5215AA697007AC99D /* UnitTests */,
-                               5E3B95A121CAC6C500C0A151 /* APIv2Tests */,
-                               B0BB3EF6225E795F008DA580 /* MacTests */,
+                       name = "[CP] Check Pods Manifest.lock";
+                       outputFileListPaths = (
                        );
-               };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-               5E0282E4215AA697007AC99D /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/Pods-CronetTests-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;
                };
-               5E3B95A021CAC6C500C0A151 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
+               D11CB94CF56A1E53760D29D8 /* [CP] Copy Pods Resources */ = {
+                       isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E7D71B0210B9EC8001EA6BA /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                       inputPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-resources.sh",
+                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle",
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E8A5DA21D3840B4000F8BC4 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                       name = "[CP] Copy Pods Resources";
+                       outputPaths = (
+                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-resources.sh\"\n";
+                       showEnvVarsInLog = 0;
                };
-               5EAD6D221E27047400002378 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
+               E5B20F69559C6AE299DFEA7C /* [CP] Check Pods Manifest.lock */ = {
+                       isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2E22107DED300EB4B69 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                       inputFileListPaths = (
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2F32109284500EB4B69 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */,
+                       inputPaths = (
+                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+                               "${PODS_ROOT}/Manifest.lock",
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E41F208177CC000EF4AD /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                       name = "[CP] Check Pods Manifest.lock";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/Pods-MacTests-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;
                };
-               5EC5E42F2081856B000EF4AD /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E440208185CE000EF4AD /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EC5E44E20818948000EF4AD /* TestCertificates.bundle in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EE84BEF1D4717E40050C6CC /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63423F421B150A5F006CF63C /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84111BE15179000708E8 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84211BE15267000708E8 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84321BE15294000708E8 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84411BE152B5000708E8 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               B0BB3EF5225E795F008DA580 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               B0BB3F0A225EA511008DA580 /* TestCertificates.bundle in Resources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
-               021B3B1F545989843EBC9A4B /* [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-ChannelTests-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;
-               };
-               0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               1EAF0CBDBFAB18D4DA64535D /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-ChannelTests/Pods-ChannelTests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               252A376345E38FD452A89C3D /* [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-InteropTestsLocalCleartextCFStream-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;
-               };
-               2865C6386D677998F861E183 /* [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-InteropTestsCallOptions-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;
-               };
-               31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-frameworks.sh",
-                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
-                       );
-                       name = "[CP] Embed Pods Frameworks";
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-frameworks.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               452FDC3918FEC23ECAFD31EC /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputFileListPaths = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-MacTests/Pods-MacTests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-macOS/gRPCCertificates.bundle",
-                       );
-                       name = "[CP] Copy Pods Resources";
-                       outputFileListPaths = (
-                       );
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MacTests/Pods-MacTests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               483CDBBAEAEFCB530ADDDDD5 /* [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-InteropTestsRemoteCFStream-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;
-               };
-               4C406327D3907A5E5FBA8AC9 /* [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-InteropTestsRemote-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;
-               };
-               4EB2FFF40BB00AD0C545D7EF /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               5C20DCCB71C3991E6FE78C22 /* [CP] Check Pods Manifest.lock */ = {
-                       isa = PBXShellScriptBuildPhase;
+               F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */ = {
+                       isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        );
                        name = "[CP] Check Pods Manifest.lock";
                        outputPaths = (
-                               "$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalSSL-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;
-               };
-               693DD0B453431D64EA24FD66 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               6BA6D00B1816306453BF82D4 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle",
-                       );
-                       name = "[CP] Copy Pods Resources";
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
+                               "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               7418AC7B3844B29E48D24FC7 /* [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-InteropTestsLocalCleartext-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;
-               };
-               80E2DDD2EC04A4009F45E933 /* [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-CronetUnitTests-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;
-               };
-               8AD3130D3C58A0FB32FF2A36 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               8C1ED025E07C4D457C355336 /* [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-InteropTestsMultipleChannels-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;
-               };
-               8D685CB612835DB3F7A6F14A /* [CP] Embed Pods Frameworks */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-frameworks.sh",
-                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
-                       );
-                       name = "[CP] Embed Pods Frameworks";
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-frameworks.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               914ADDD7106BA9BB8A7E569F /* [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-AllTests-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;
-               };
-               95FBC48B743503845678584F /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-UnitTests/Pods-UnitTests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               A023FB55205A7EA37D413549 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               A441F71824DCB9D0CA297748 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-AllTests/Pods-AllTests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               A686B9967BB4CB81B1CBF8F8 /* [CP] Embed Pods Frameworks */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-frameworks.sh",
-                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
-                       );
-                       name = "[CP] Embed Pods Frameworks";
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-frameworks.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               B2986CEEE8CDD4901C97598B /* [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-RxLibraryUnitTests-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;
-               };
-               C0F7B1FF6F88CC5FBF362F4C /* [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-InteropTestsRemoteWithCronet-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;
-               };
-               C17B826BBD02FDD4A5F355AF /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputFileListPaths = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle",
-                       );
-                       name = "[CP] Copy Pods Resources";
-                       outputFileListPaths = (
-                       );
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               C977426A8727267BBAC7D48E /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               DB4D0E73C229F2FF3B364AB3 /* [CP] Copy Pods Resources */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh",
-                               "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/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-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               E5B20F69559C6AE299DFEA7C /* [CP] Check Pods Manifest.lock */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputFileListPaths = (
-                       );
-                       inputPaths = (
-                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-                               "${PODS_ROOT}/Manifest.lock",
-                       );
-                       name = "[CP] Check Pods Manifest.lock";
-                       outputFileListPaths = (
-                       );
-                       outputPaths = (
-                               "$(DERIVED_FILE_DIR)/Pods-MacTests-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;
-               };
-               E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh",
-                               "${PODS_ROOT}/CronetFramework/Cronet.framework",
-                       );
-                       name = "[CP] Embed Pods Frameworks";
-                       outputPaths = (
-                               "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n";
-                       showEnvVarsInLog = 0;
-               };
-               EDDD3FA856BCA3443ED36D1E /* [CP] Check Pods Manifest.lock */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputFileListPaths = (
-                       );
-                       inputPaths = (
-                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-                               "${PODS_ROOT}/Manifest.lock",
-                       );
-                       name = "[CP] Check Pods Manifest.lock";
-                       outputFileListPaths = (
-                       );
-                       outputPaths = (
-                               "$(DERIVED_FILE_DIR)/Pods-APIv2Tests-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;
-               };
-               F07941C0BAF6A7C67AA60C48 /* [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-UnitTests-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;
-               };
-               F3D5B2CDA172580341682830 /* [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-InteropTestsLocalSSLCFStream-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;
-               };
-               F58F17E425446B15028B9F74 /* [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-CoreCronetEnd2EndTests-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;
-               };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-               5E0282E2215AA697007AC99D /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E0282E9215AA697007AC99D /* UnitTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E3B959E21CAC6C500C0A151 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E3B95A521CAC6C500C0A151 /* APIv2Tests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E7D71AE210B9EC8001EA6BA /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5E8A5DA01D3840B4000F8BC4 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EAD6D201E27047400002378 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2E02107DED300EB4B69 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EB2A2E72107DED300EB4B69 /* ChannelTests.m in Sources */,
-                               5EB5C3AA21656CEA00ADC300 /* ChannelPoolTest.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EB2A2F12109284500EB4B69 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EB2A2F82109284500EB4B69 /* InteropTestsMultipleChannels.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E41D208177CC000EF4AD /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EC5E42B2081782C000EF4AD /* InteropTestsRemote.m in Sources */,
-                               5EC5E42C20817832000EF4AD /* InteropTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E42D2081856B000EF4AD /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EC5E43B208185A7000EF4AD /* InteropTestsLocalCleartext.m in Sources */,
-                               5EC5E43D208185B0000EF4AD /* GRPCClientTests.m in Sources */,
-                               5EC5E43C208185AD000EF4AD /* InteropTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EC5E43E208185CE000EF4AD /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EC5E44D208185F0000EF4AD /* InteropTestsLocalSSL.m in Sources */,
-                               5EC5E44C208185EC000EF4AD /* InteropTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               5EE84BED1D4717E40050C6CC /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               5EE84BFE1D471D400050C6CC /* InteropTests.m in Sources */,
-                               5EE84BF41D4717E40050C6CC /* InteropTestsRemoteWithCronet.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63423F401B150A5F006CF63C /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */,
-                               6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */,
-                               63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */,
-                               6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */,
-                               635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */,
-                               63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               635697C31B14FC11007A7283 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               635697CD1B14FC11007A7283 /* Tests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC840F1BE15179000708E8 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC841F1BE15267000708E8 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */,
-                               6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC84301BE15294000708E8 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */,
-                               6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               63DC843F1BE152B5000708E8 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */,
-                               63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */,
-                               6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               B0BB3EF3225E795F008DA580 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               B0BB3F07225E7AB5008DA580 /* APIv2Tests.m in Sources */,
-                               B0BB3F08225E7ABA008DA580 /* UnitTests.m in Sources */,
-                               B071230B22669EED004B64A1 /* StressTests.m in Sources */,
-                               B0BB3F05225E7A9F008DA580 /* InteropTestsRemote.m in Sources */,
-                               B0D39B9A2266F3CB00A4078D /* StressTestsSSL.m in Sources */,
-                               B0BB3F03225E7A44008DA580 /* InteropTestsLocalCleartext.m in Sources */,
-                               B0BB3F04225E7A8D008DA580 /* RxLibraryUnitTests.m in Sources */,
-                               B0D39B9C2266FF9800A4078D /* StressTestsCleartext.m in Sources */,
-                               B0BB3F0B225EB110008DA580 /* InteropTests.m in Sources */,
-                               B0BB3F02225E7A3C008DA580 /* InteropTestsLocalSSL.m in Sources */,
-                               B0BB3F06225E7AAD008DA580 /* GRPCClientTests.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
-               5E0282ED215AA697007AC99D /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */;
-               };
-               5E7D71B9210B9EC9001EA6BA /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5E7D71B8210B9EC9001EA6BA /* PBXContainerItemProxy */;
-               };
-               5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */;
-               };
-               5EAD6D2B1E27047400002378 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5EAD6D2A1E27047400002378 /* PBXContainerItemProxy */;
-               };
-               5EB2A2EB2107DED300EB4B69 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5EB2A2EA2107DED300EB4B69 /* PBXContainerItemProxy */;
-               };
-               5EB2A2FC2109284500EB4B69 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5EB2A2FB2109284500EB4B69 /* PBXContainerItemProxy */;
-               };
-               5EE84BF81D4717E40050C6CC /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */;
-               };
-               63423F4C1B150A5F006CF63C /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 63423F4B1B150A5F006CF63C /* PBXContainerItemProxy */;
-               };
-               63DC841A1BE15179000708E8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 63DC84191BE15179000708E8 /* PBXContainerItemProxy */;
-               };
-               63DC842A1BE15267000708E8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 63DC84291BE15267000708E8 /* PBXContainerItemProxy */;
-               };
-               63DC843B1BE15294000708E8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 63DC843A1BE15294000708E8 /* PBXContainerItemProxy */;
-               };
-               63DC844A1BE152B5000708E8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 635697C61B14FC11007A7283 /* Tests */;
-                       targetProxy = 63DC84491BE152B5000708E8 /* PBXContainerItemProxy */;
-               };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
-               5E0282EE215AA697007AC99D /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = UnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
-                       };
-                       name = Debug;
-               };
-               5E0282EF215AA697007AC99D /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = UnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
-                       };
-                       name = Test;
-               };
-               5E0282F0215AA697007AC99D /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = UnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
-                       };
-                       name = Cronet;
-               };
-               5E0282F1215AA697007AC99D /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = UnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
-                       };
-                       name = Release;
-               };
-               5E1228981E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                                       "HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)",
-                                       "HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)",
-                                       "HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_TREAT_WARNINGS_AS_ERRORS = 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;
-                               IPHONEOS_DEPLOYMENT_TARGET = 8.3;
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               SDKROOT = iphoneos;
-                       };
-                       name = Test;
-               };
-               5E1228991E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Test;
-               };
-               5E12289A1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = DB1F4391AF69D20D38D74B67 /* Pods-AllTests.test.xcconfig */;
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(SDKROOT)/Developer/Library/Frameworks",
-                                       "$(inherited)",
-                               );
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E12289B1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 781089FAE980F51F88A3BE0B /* Pods-RxLibraryUnitTests.test.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E12289C1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = A6F832FCEFA6F6881E620F12 /* Pods-InteropTestsRemote.test.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E12289D1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = D13BEC8181B8E678A1B52F54 /* Pods-InteropTestsLocalSSL.test.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E12289E1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E12289F1E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 6793C9D019CB268C5BB491A2 /* Pods-CoreCronetEnd2EndTests.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
-                       };
-                       name = Test;
-               };
-               5E1228A01E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 2B89F3037963E6EDDD48D8C3 /* Pods-InteropTestsRemoteWithCronet.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Test;
-               };
-               5E1228A11E4D400F00E8504F /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = B226619DC4E709E0FFFF94B8 /* Pods-CronetUnitTests.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
-                               INFOPLIST_FILE = CronetUnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
-                       };
-                       name = Test;
-               };
-               5E3B95A821CAC6C500C0A151 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = APIv2Tests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Debug;
-               };
-               5E3B95A921CAC6C500C0A151 /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = APIv2Tests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Test;
-               };
-               5E3B95AA21CAC6C500C0A151 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = APIv2Tests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Cronet;
-               };
-               5E3B95AB21CAC6C500C0A151 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = APIv2Tests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               MTL_FAST_MATH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Release;
-               };
-               5E7D71BB210B9EC9001EA6BA /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 3A98DF08852F60AF1D96481D /* Pods-InteropTestsCallOptions.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsCallOptions/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Debug;
-               };
-               5E7D71BC210B9EC9001EA6BA /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = A25967A0D40ED14B3287AD81 /* Pods-InteropTestsCallOptions.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsCallOptions/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Test;
-               };
-               5E7D71BD210B9EC9001EA6BA /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 73D2DF07027835BA0FB0B1C0 /* Pods-InteropTestsCallOptions.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsCallOptions/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Cronet;
-               };
-               5E7D71BE210B9EC9001EA6BA /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = C9172F9020E8C97A470D7250 /* Pods-InteropTestsCallOptions.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsCallOptions/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Release;
-               };
-               5E8A5DAC1D3840B4000F8BC4 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               LIBRARY_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/BoringSSL\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/RemoteTest\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core-072e2d32\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-ProtoRPC\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-RxLibrary\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb\"",
-                                       "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"",
-                               );
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
-                       };
-                       name = Debug;
-               };
-               5E8A5DAD1D3840B4000F8BC4 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
-                       };
-                       name = Release;
-               };
-               5EAD6D2C1E27047400002378 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "PB_FIELD_32BIT=1",
-                                       "PB_NO_PACKED_STRUCTS=1",
-                                       "GRPC_SHADOW_BORINGSSL_SYMBOLS=1",
-                               );
-                               INFOPLIST_FILE = CronetUnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
-                       };
-                       name = Debug;
-               };
-               5EAD6D2D1E27047400002378 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 386712AEACF7C2190C4B8B3F /* Pods-CronetUnitTests.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
-                               INFOPLIST_FILE = CronetUnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
-                       };
-                       name = Cronet;
-               };
-               5EAD6D2E1E27047400002378 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 02192CF1FF9534E3D18C65FC /* Pods-CronetUnitTests.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
-                               INFOPLIST_FILE = CronetUnitTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
-                       };
-                       name = Release;
-               };
-               5EB2A2EC2107DED300EB4B69 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = F9E48EF5ACB1F38825171C5F /* Pods-ChannelTests.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = ChannelTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Debug;
-               };
-               5EB2A2ED2107DED300EB4B69 /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = BED74BC8ABF9917C66175879 /* Pods-ChannelTests.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = ChannelTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Test;
-               };
-               5EB2A2EE2107DED300EB4B69 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = ChannelTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Cronet;
-               };
-               5EB2A2EF2107DED300EB4B69 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = D52B92A7108602F170DA8091 /* Pods-ChannelTests.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = ChannelTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Release;
-               };
-               5EB2A2FD2109284500EB4B69 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 3CADF86203B9D03EA96C359D /* Pods-InteropTestsMultipleChannels.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Debug;
-               };
-               5EB2A2FE2109284500EB4B69 /* Test */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = EA8B122ACDE73E3AAA0E4A19 /* Pods-InteropTestsMultipleChannels.test.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Test;
-               };
-               5EB2A2FF2109284500EB4B69 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 1295CCBD1082B4A7CFCED95F /* Pods-InteropTestsMultipleChannels.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Cronet;
-               };
-               5EB2A3002109284500EB4B69 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 2650FEF00956E7924772F9D9 /* Pods-InteropTestsMultipleChannels.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Release;
-               };
-               5EC3C7A01D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = YES;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_ENUM_CONVERSION = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               COPY_PHASE_STRIP = NO;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_NO_COMMON_BLOCKS = YES;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                                       "HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
-                                       "HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)",
-                                       "HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_TREAT_WARNINGS_AS_ERRORS = 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;
-                               IPHONEOS_DEPLOYMENT_TARGET = 8.3;
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               SDKROOT = iphoneos;
-                       };
-                       name = Cronet;
-               };
-               5EC3C7A11D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Cronet;
-               };
-               5EC3C7A21D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */;
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(SDKROOT)/Developer/Library/Frameworks",
-                                       "$(inherited)",
-                               );
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
-               };
-               5EC3C7A31D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
-               };
-               5EC3C7A41D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                               );
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
-               };
-               5EC3C7A51D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
+                       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;
                };
-               5EC3C7A61D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               5E0282E2215AA697007AC99D /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5E0282E9215AA697007AC99D /* NSErrorUnitTests.m in Sources */,
+                               5E7F4880227782C1006656AD /* APIv2Tests.m in Sources */,
+                               5E7F487D22778256006656AD /* ChannelPoolTest.m in Sources */,
+                               5E7F488722778AEA006656AD /* GRPCClientTests.m in Sources */,
+                               5E7F487E22778256006656AD /* ChannelTests.m in Sources */,
+                               5E7F488B22778B5D006656AD /* RxLibraryUnitTests.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
                };
-               5EC3C7A71D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
-                       };
-                       name = Cronet;
+               5E7F485522775B15006656AD /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5E3F14852278BF5D007C6D90 /* InteropTestsBlockCallbacks.m in Sources */,
+                               5E3F148D22792856007C6D90 /* ConfigureCronet.m in Sources */,
+                               5E7F486E22778086006656AD /* CoreCronetEnd2EndTests.mm in Sources */,
+                               5E7F488522778A88006656AD /* InteropTests.m in Sources */,
+                               5E7F486422775B37006656AD /* InteropTestsRemoteWithCronet.m in Sources */,
+                               5E7F486522775B41006656AD /* CronetUnitTests.mm in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
                };
-               5EC3C7A81D4FC18C000330E2 /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_COMPILE_WITH_CRONET=1",
-                                       "GRPC_CRONET_WITH_PACKET_COALESCING=1",
-                                       "GRPC_TEST_OBJC=1",
-                               );
-                               INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Cronet;
+               5EA476F02272816A000F72FC /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5E3F14842278B461007C6D90 /* InteropTestsBlockCallbacks.m in Sources */,
+                               5E3F148E22792AF5007C6D90 /* ConfigureCronet.m in Sources */,
+                               5E7F488922778B04006656AD /* InteropTestsRemote.m in Sources */,
+                               5E7F487922778226006656AD /* InteropTestsMultipleChannels.m in Sources */,
+                               5EA477042273617B000F72FC /* InteropTestsLocalCleartext.m in Sources */,
+                               5EA4770322736178000F72FC /* InteropTestsLocalSSL.m in Sources */,
+                               5E7F488422778A88006656AD /* InteropTests.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               B0BB3EF3225E795F008DA580 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               B0BB3F08225E7ABA008DA580 /* NSErrorUnitTests.m in Sources */,
+                               5E7F488D22778C85006656AD /* InteropTestsLocalSSL.m in Sources */,
+                               5E7F488E22778C87006656AD /* InteropTestsLocalCleartext.m in Sources */,
+                               5E7F489022778C95006656AD /* RxLibraryUnitTests.m in Sources */,
+                               B071230B22669EED004B64A1 /* StressTests.m in Sources */,
+                               B0D39B9A2266F3CB00A4078D /* StressTestsSSL.m in Sources */,
+                               5E7F488322778A88006656AD /* InteropTests.m in Sources */,
+                               5E3F14862278BFFF007C6D90 /* InteropTestsBlockCallbacks.m in Sources */,
+                               5E7F488C22778C60006656AD /* APIv2Tests.m in Sources */,
+                               5E7F488F22778C8C006656AD /* InteropTestsRemote.m in Sources */,
+                               B0D39B9C2266FF9800A4078D /* StressTestsCleartext.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
                };
-               5EC5E426208177CC000EF4AD /* Debug */ = {
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+               5E0282EE215AA697007AC99D /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 32748C4078AEB05F8F954361 /* Pods-InteropTestsRemoteCFStream.debug.xcconfig */;
+                       baseConfigurationReference = A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                ENABLE_TESTABILITY = YES;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteCFStream;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
                        };
                        name = Debug;
                };
-               5EC5E427208177CC000EF4AD /* Test */ = {
+               5E0282EF215AA697007AC99D /* Test */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = C17F57E5BCB989AB1C2F1F25 /* Pods-InteropTestsRemoteCFStream.test.xcconfig */;
+                       baseConfigurationReference = 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "$(inherited)",
-                                       "PB_FIELD_32BIT=1",
-                                       "PB_NO_PACKED_STRUCTS=1",
-                                       "GRPC_CFSTREAM=1",
-                               );
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteCFStream;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
                        };
                        name = Test;
                };
-               5EC5E428208177CC000EF4AD /* Cronet */ = {
+               5E0282F0215AA697007AC99D /* Cronet */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 4A1A42B2E941CCD453489E5B /* Pods-InteropTestsRemoteCFStream.cronet.xcconfig */;
+                       baseConfigurationReference = E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CODE_SIGN_STYLE = Automatic;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteCFStream;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
                        };
                        name = Cronet;
                };
-               5EC5E429208177CC000EF4AD /* Release */ = {
+               5E0282F1215AA697007AC99D /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 303F4A17EB1650FC44603D17 /* Pods-InteropTestsRemoteCFStream.release.xcconfig */;
+                       baseConfigurationReference = EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CODE_SIGN_STYLE = Automatic;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteCFStream;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
                        };
                        name = Release;
                };
-               5EC5E4372081856C000EF4AD /* Debug */ = {
+               5E1228981E4D400F00E8504F /* Test */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                                       "HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)",
+                                       "HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)",
+                                       "HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
+                                       "GRPC_TEST_OBJC=1",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = 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;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = iphoneos;
+                       };
+                       name = Test;
+               };
+               5E7F485F22775B15006656AD /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 943138072A9605B5B8DC1FC0 /* Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig */;
+                       baseConfigurationReference = EC66920112123D2DB1CB7F6C /* Pods-CronetTests.debug.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CODE_SIGN_STYLE = Automatic;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_TESTABILITY = YES;
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(PROJECT_DIR)/Pods/CronetFramework",
+                               );
                                GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartextCFStream;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = ../../..;
                        };
                        name = Debug;
                };
-               5EC5E4382081856C000EF4AD /* Test */ = {
+               5E7F486022775B15006656AD /* Test */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = E4FD4606D4AB8D5A314D72F0 /* Pods-InteropTestsLocalCleartextCFStream.test.xcconfig */;
+                       baseConfigurationReference = 5AB9A82F289D548D6B8816F9 /* Pods-CronetTests.test.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
+                               FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
-                                       "PB_FIELD_32BIT=1",
-                                       "PB_NO_PACKED_STRUCTS=1",
-                                       "GRPC_CFSTREAM=1",
+                                       "$(PROJECT_DIR)/Pods/CronetFramework",
                                );
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartextCFStream;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = ../../..;
                        };
                        name = Test;
                };
-               5EC5E4392081856C000EF4AD /* Cronet */ = {
+               5E7F486122775B15006656AD /* Cronet */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */;
+                       baseConfigurationReference = 20F6A3D59D0EE091E2D43953 /* Pods-CronetTests.cronet.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(PROJECT_DIR)/Pods/CronetFramework",
+                               );
                                GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartextCFStream;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = ../../..;
                        };
                        name = Cronet;
                };
-               5EC5E43A2081856C000EF4AD /* Release */ = {
+               5E7F486222775B15006656AD /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */;
+                       baseConfigurationReference = 7F4F42EBAF311E9F84FCA32E /* Pods-CronetTests.release.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(PROJECT_DIR)/Pods/CronetFramework",
+                               );
                                GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartextCFStream;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               USER_HEADER_SEARCH_PATHS = ../../..;
                        };
                        name = Release;
                };
-               5EC5E448208185CE000EF4AD /* Debug */ = {
+               5EA476FC2272816B000F72FC /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 3EB55EF291706E3DDE23C3B7 /* Pods-InteropTestsLocalSSLCFStream.debug.xcconfig */;
+                       baseConfigurationReference = 680439AC2BC8761EDD54A1EA /* Pods-InteropTests.debug.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                ENABLE_TESTABILITY = YES;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSLCFStream;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
                        };
                        name = Debug;
                };
-               5EC5E449208185CE000EF4AD /* Test */ = {
+               5EA476FD2272816B000F72FC /* Test */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 41AA59529240A6BBBD3DB904 /* Pods-InteropTestsLocalSSLCFStream.test.xcconfig */;
+                       baseConfigurationReference = 070266E2626EB997B54880A3 /* Pods-InteropTests.test.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "$(inherited)",
-                                       "PB_FIELD_32BIT=1",
-                                       "PB_NO_PACKED_STRUCTS=1",
-                                       "GRPC_CFSTREAM=1",
-                               );
                                INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSLCFStream;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
                        };
                        name = Test;
                };
-               5EC5E44A208185CE000EF4AD /* Cronet */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-                               CLANG_WARN_INFINITE_RECURSION = YES;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
-                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CODE_SIGN_IDENTITY = "iPhone Developer";
-                               CODE_SIGN_STYLE = Automatic;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSLCFStream;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Cronet;
-               };
-               5EC5E44B208185CE000EF4AD /* Release */ = {
+               5EA476FE2272816B000F72FC /* Cronet */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */;
+                       baseConfigurationReference = CDF6CC70B8BF9D10EFE7D199 /* Pods-InteropTests.cronet.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CODE_SIGN_IDENTITY = "iPhone Developer";
                                CODE_SIGN_STYLE = Automatic;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.2;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSLCFStream;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Release;
-               };
-               5EE84BF91D4717E40050C6CC /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                               );
-                               INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               5EE84BFA1D4717E40050C6CC /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */;
-                       buildSettings = {
-                               CLANG_ANALYZER_NONNULL = YES;
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "$(inherited)",
-                                       "COCOAPODS=1",
-                                       "$(inherited)",
-                                       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
-                                       "GRPC_COMPILE_WITH_CRONET=1",
-                               );
-                               INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+                               INFOPLIST_FILE = Info.plist;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               TARGETED_DEVICE_FAMILY = "1,2";
                        };
-                       name = Release;
+                       name = Cronet;
                };
-               63423F4E1B150A5F006CF63C /* Debug */ = {
+               5EA476FF2272816B000F72FC /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */;
+                       baseConfigurationReference = F6A7EECACBB4849DDD3F450A /* Pods-InteropTests.release.xcconfig */;
                        buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(SDKROOT)/Developer/Library/Frameworks",
-                                       "$(inherited)",
-                               );
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+                               CODE_SIGN_IDENTITY = "iPhone Developer";
+                               CODE_SIGN_STYLE = Automatic;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                INFOPLIST_FILE = Info.plist;
                                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               TARGETED_DEVICE_FAMILY = "1,2";
                        };
-                       name = Debug;
+                       name = Release;
                };
-               63423F4F1B150A5F006CF63C /* Release */ = {
+               5EC3C7A01D4FC18C000330E2 /* Cronet */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */;
                        buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(SDKROOT)/Developer/Library/Frameworks",
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
                                        "$(inherited)",
+                                       "HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
+                                       "HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)",
+                                       "HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)",
+                                       "GRPC_TEST_OBJC=1",
+                                       "GRPC_COMPILE_WITH_CRONET=1",
                                );
-                               INFOPLIST_FILE = Info.plist;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = 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;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = iphoneos;
                        };
-                       name = Release;
+                       name = Cronet;
                };
                635697D91B14FC11007A7283 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        };
                        name = Release;
                };
-               635697DC1B14FC11007A7283 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Debug;
-               };
-               635697DD1B14FC11007A7283 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SKIP_INSTALL = YES;
-                       };
-                       name = Release;
-               };
-               63DC841C1BE15179000708E8 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               63DC841D1BE15179000708E8 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Release;
-               };
-               63DC842C1BE15267000708E8 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               63DC842D1BE15267000708E8 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Release;
-               };
-               63DC843D1BE15294000708E8 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               63DC843E1BE15294000708E8 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Release;
-               };
-               63DC844C1BE152B5000708E8 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENABLE_TESTABILITY = YES;
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               63DC844D1BE152B5000708E8 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Info.plist;
-                               IPHONEOS_DEPLOYMENT_TARGET = 9.0;
-                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-                               PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Release;
-               };
                B0BB3EFD225E795F008DA580 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = E3ACD4D5902745976D9C2229 /* Pods-MacTests.debug.xcconfig */;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               5E3B95A721CAC6C500C0A151 /* Build configuration list for PBXNativeTarget "APIv2Tests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5E3B95A821CAC6C500C0A151 /* Debug */,
-                               5E3B95A921CAC6C500C0A151 /* Test */,
-                               5E3B95AA21CAC6C500C0A151 /* Cronet */,
-                               5E3B95AB21CAC6C500C0A151 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5E7D71BB210B9EC9001EA6BA /* Debug */,
-                               5E7D71BC210B9EC9001EA6BA /* Test */,
-                               5E7D71BD210B9EC9001EA6BA /* Cronet */,
-                               5E7D71BE210B9EC9001EA6BA /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5E8A5DAC1D3840B4000F8BC4 /* Debug */,
-                               5E12289F1E4D400F00E8504F /* Test */,
-                               5EC3C7A71D4FC18C000330E2 /* Cronet */,
-                               5E8A5DAD1D3840B4000F8BC4 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EAD6D2F1E27047400002378 /* Build configuration list for PBXNativeTarget "CronetUnitTests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EAD6D2C1E27047400002378 /* Debug */,
-                               5E1228A11E4D400F00E8504F /* Test */,
-                               5EAD6D2D1E27047400002378 /* Cronet */,
-                               5EAD6D2E1E27047400002378 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EB2A2F02107DED300EB4B69 /* Build configuration list for PBXNativeTarget "ChannelTests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EB2A2EC2107DED300EB4B69 /* Debug */,
-                               5EB2A2ED2107DED300EB4B69 /* Test */,
-                               5EB2A2EE2107DED300EB4B69 /* Cronet */,
-                               5EB2A2EF2107DED300EB4B69 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EB2A3012109284500EB4B69 /* Build configuration list for PBXNativeTarget "InteropTestsMultipleChannels" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EB2A2FD2109284500EB4B69 /* Debug */,
-                               5EB2A2FE2109284500EB4B69 /* Test */,
-                               5EB2A2FF2109284500EB4B69 /* Cronet */,
-                               5EB2A3002109284500EB4B69 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EC5E42A208177CD000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsRemoteCFStream" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EC5E426208177CC000EF4AD /* Debug */,
-                               5EC5E427208177CC000EF4AD /* Test */,
-                               5EC5E428208177CC000EF4AD /* Cronet */,
-                               5EC5E429208177CC000EF4AD /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EC5E4362081856C000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartextCFStream" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EC5E4372081856C000EF4AD /* Debug */,
-                               5EC5E4382081856C000EF4AD /* Test */,
-                               5EC5E4392081856C000EF4AD /* Cronet */,
-                               5EC5E43A2081856C000EF4AD /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EC5E447208185CE000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSLCFStream" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               5EC5E448208185CE000EF4AD /* Debug */,
-                               5EC5E449208185CE000EF4AD /* Test */,
-                               5EC5E44A208185CE000EF4AD /* Cronet */,
-                               5EC5E44B208185CE000EF4AD /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */ = {
+               5E7F485E22775B15006656AD /* Build configuration list for PBXNativeTarget "CronetTests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               5EE84BF91D4717E40050C6CC /* Debug */,
-                               5E1228A01E4D400F00E8504F /* Test */,
-                               5EC3C7A81D4FC18C000330E2 /* Cronet */,
-                               5EE84BFA1D4717E40050C6CC /* Release */,
+                               5E7F485F22775B15006656AD /* Debug */,
+                               5E7F486022775B15006656AD /* Test */,
+                               5E7F486122775B15006656AD /* Cronet */,
+                               5E7F486222775B15006656AD /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */ = {
+               5EA477002272816B000F72FC /* Build configuration list for PBXNativeTarget "InteropTests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               63423F4E1B150A5F006CF63C /* Debug */,
-                               5E12289A1E4D400F00E8504F /* Test */,
-                               5EC3C7A21D4FC18C000330E2 /* Cronet */,
-                               63423F4F1B150A5F006CF63C /* Release */,
+                               5EA476FC2272816B000F72FC /* Debug */,
+                               5EA476FD2272816B000F72FC /* Test */,
+                               5EA476FE2272816B000F72FC /* Cronet */,
+                               5EA476FF2272816B000F72FC /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               635697DB1B14FC11007A7283 /* Build configuration list for PBXNativeTarget "Tests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               635697DC1B14FC11007A7283 /* Debug */,
-                               5E1228991E4D400F00E8504F /* Test */,
-                               5EC3C7A11D4FC18C000330E2 /* Cronet */,
-                               635697DD1B14FC11007A7283 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               63DC841B1BE15179000708E8 /* Build configuration list for PBXNativeTarget "RxLibraryUnitTests" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               63DC841C1BE15179000708E8 /* Debug */,
-                               5E12289B1E4D400F00E8504F /* Test */,
-                               5EC3C7A31D4FC18C000330E2 /* Cronet */,
-                               63DC841D1BE15179000708E8 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               63DC842B1BE15267000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsRemote" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               63DC842C1BE15267000708E8 /* Debug */,
-                               5E12289C1E4D400F00E8504F /* Test */,
-                               5EC3C7A41D4FC18C000330E2 /* Cronet */,
-                               63DC842D1BE15267000708E8 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               63DC843C1BE15294000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSL" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               63DC843D1BE15294000708E8 /* Debug */,
-                               5E12289D1E4D400F00E8504F /* Test */,
-                               5EC3C7A51D4FC18C000330E2 /* Cronet */,
-                               63DC843E1BE15294000708E8 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               63DC844B1BE152B5000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartext" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               63DC844C1BE152B5000708E8 /* Debug */,
-                               5E12289E1E4D400F00E8504F /* Test */,
-                               5EC3C7A61D4FC18C000330E2 /* Cronet */,
-                               63DC844D1BE152B5000708E8 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                B0BB3EFC225E795F008DA580 /* Build configuration list for PBXNativeTarget "MacTests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme
deleted file mode 100644 (file)
index e0d1d1f..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1000"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
-               BuildableName = "APIv2Tests.xctest"
-               BlueprintName = "APIv2Tests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
-               BuildableName = "APIv2Tests.xctest"
-               BlueprintName = "APIv2Tests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
-            BuildableName = "APIv2Tests.xctest"
-            BlueprintName = "APIv2Tests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
-            BuildableName = "APIv2Tests.xctest"
-            BlueprintName = "APIv2Tests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
deleted file mode 100644 (file)
index a2560fe..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0630"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63423F431B150A5F006CF63C"
-               BuildableName = "AllTests.xctest"
-               BlueprintName = "AllTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63423F431B150A5F006CF63C"
-               BuildableName = "AllTests.xctest"
-               BlueprintName = "AllTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-               <Test
-                  Identifier = "LocalClearTextTests">
-               </Test>
-               <Test
-                  Identifier = "LocalClearTextTests/testConnectionToLocalServer">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63423F431B150A5F006CF63C"
-            BuildableName = "AllTests.xctest"
-            BlueprintName = "AllTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63423F431B150A5F006CF63C"
-            BuildableName = "AllTests.xctest"
-            BlueprintName = "AllTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63423F431B150A5F006CF63C"
-            BuildableName = "AllTests.xctest"
-            BlueprintName = "AllTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Test">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme
deleted file mode 100644 (file)
index acae965..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0930"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
-               BuildableName = "ChannelTests.xctest"
-               BlueprintName = "ChannelTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
-               BuildableName = "ChannelTests.xctest"
-               BlueprintName = "ChannelTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
-            BuildableName = "ChannelTests.xctest"
-            BlueprintName = "ChannelTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
-            BuildableName = "ChannelTests.xctest"
-            BlueprintName = "ChannelTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
deleted file mode 100644 (file)
index e62edd3..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0730"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-               BuildableName = "CoreCronetEnd2EndTests.xctest"
-               BlueprintName = "CoreCronetEnd2EndTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-               BuildableName = "CoreCronetEnd2EndTests.xctest"
-               BlueprintName = "CoreCronetEnd2EndTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-            BuildableName = "CoreCronetEnd2EndTests.xctest"
-            BlueprintName = "CoreCronetEnd2EndTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-            BuildableName = "CoreCronetEnd2EndTests.xctest"
-            BlueprintName = "CoreCronetEnd2EndTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-            BuildableName = "CoreCronetEnd2EndTests.xctest"
-            BlueprintName = "CoreCronetEnd2EndTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme
deleted file mode 100644 (file)
index 0a597e7..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0920"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      enableAddressSanitizer = "YES"
-      enableASanStackUseAfterReturn = "YES"
-      language = ""
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-               BuildableName = "CoreCronetEnd2EndTests.xctest"
-               BlueprintName = "CoreCronetEnd2EndTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme
deleted file mode 100644 (file)
index 5fe60b9..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0920"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      enableThreadSanitizer = "YES"
-      language = ""
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
-               BuildableName = "CoreCronetEnd2EndTests.xctest"
-               BlueprintName = "CoreCronetEnd2EndTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0700"
+   LastUpgradeVersion = "1010"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
             buildForRunning = "YES"
             buildForProfiling = "NO"
             buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
+            buildForAnalyzing = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84331BE15294000708E8"
-               BuildableName = "InteropTestsLocalSSL.xctest"
-               BlueprintName = "InteropTestsLocalSSL"
+               BlueprintIdentifier = "5E7F485822775B15006656AD"
+               BuildableName = "CronetTests.xctest"
+               BlueprintName = "CronetTests"
                ReferencedContainer = "container:Tests.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
-      buildConfiguration = "Test"
+      buildConfiguration = "Cronet"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
@@ -32,9 +32,9 @@
             skipped = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84331BE15294000708E8"
-               BuildableName = "InteropTestsLocalSSL.xctest"
-               BlueprintName = "InteropTestsLocalSSL"
+               BlueprintIdentifier = "5E7F485822775B15006656AD"
+               BuildableName = "CronetTests.xctest"
+               BlueprintName = "CronetTests"
                ReferencedContainer = "container:Tests.xcodeproj">
             </BuildableReference>
             <SkippedTests>
             </SkippedTests>
          </TestableReference>
       </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84331BE15294000708E8"
-            BuildableName = "InteropTestsLocalSSL.xctest"
-            BlueprintName = "InteropTestsLocalSSL"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <AdditionalOptions>
       </AdditionalOptions>
    </TestAction>
    <LaunchAction
-      buildConfiguration = "Test"
+      buildConfiguration = "Cronet"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
@@ -69,9 +60,9 @@
       <MacroExpansion>
          <BuildableReference
             BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84331BE15294000708E8"
-            BuildableName = "InteropTestsLocalSSL.xctest"
-            BlueprintName = "InteropTestsLocalSSL"
+            BlueprintIdentifier = "5E7F485822775B15006656AD"
+            BuildableName = "CronetTests.xctest"
+            BlueprintName = "CronetTests"
             ReferencedContainer = "container:Tests.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Cronet"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
       debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5E7F485822775B15006656AD"
+            BuildableName = "CronetTests.xctest"
+            BlueprintName = "CronetTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
    </ProfileAction>
    <AnalyzeAction
-      buildConfiguration = "Test">
+      buildConfiguration = "Cronet">
    </AnalyzeAction>
    <ArchiveAction
       buildConfiguration = "Release"
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetUnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetUnitTests.xcscheme
deleted file mode 100644 (file)
index ea711e0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0730"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EAD6D231E27047400002378"
-               BuildableName = "CronetUnitTests.xctest"
-               BlueprintName = "CronetUnitTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0700"
+   LastUpgradeVersion = "1010"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
             buildForRunning = "YES"
             buildForProfiling = "NO"
             buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
+            buildForAnalyzing = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84221BE15267000708E8"
-               BuildableName = "InteropTestsRemote.xctest"
-               BlueprintName = "InteropTestsRemote"
+               BlueprintIdentifier = "5EA476F32272816A000F72FC"
+               BuildableName = "InteropTests.xctest"
+               BlueprintName = "InteropTests"
                ReferencedContainer = "container:Tests.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
-      buildConfiguration = "Test"
+      buildConfiguration = "Cronet"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
@@ -32,9 +32,9 @@
             skipped = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84221BE15267000708E8"
-               BuildableName = "InteropTestsRemote.xctest"
-               BlueprintName = "InteropTestsRemote"
+               BlueprintIdentifier = "5EA476F32272816A000F72FC"
+               BuildableName = "InteropTests.xctest"
+               BlueprintName = "InteropTests"
                ReferencedContainer = "container:Tests.xcodeproj">
             </BuildableReference>
             <SkippedTests>
             </SkippedTests>
          </TestableReference>
       </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84221BE15267000708E8"
-            BuildableName = "InteropTestsRemote.xctest"
-            BlueprintName = "InteropTestsRemote"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <AdditionalOptions>
       </AdditionalOptions>
    </TestAction>
    <LaunchAction
-      buildConfiguration = "Test"
+      buildConfiguration = "Cronet"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
@@ -69,9 +60,9 @@
       <MacroExpansion>
          <BuildableReference
             BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84221BE15267000708E8"
-            BuildableName = "InteropTestsRemote.xctest"
-            BlueprintName = "InteropTestsRemote"
+            BlueprintIdentifier = "5EA476F32272816A000F72FC"
+            BuildableName = "InteropTests.xctest"
+            BlueprintName = "InteropTests"
             ReferencedContainer = "container:Tests.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
       debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5EA476F32272816A000F72FC"
+            BuildableName = "InteropTests.xctest"
+            BlueprintName = "InteropTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
    </ProfileAction>
    <AnalyzeAction
-      buildConfiguration = "Test">
+      buildConfiguration = "Cronet">
    </AnalyzeAction>
    <ArchiveAction
       buildConfiguration = "Release"
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme
deleted file mode 100644 (file)
index dd83282..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0930"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5E7D71B1210B9EC8001EA6BA"
-               BuildableName = "InteropTestsCallOptions.xctest"
-               BlueprintName = "InteropTestsCallOptions"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme
deleted file mode 100644 (file)
index 11b41c9..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0700"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84421BE152B5000708E8"
-               BuildableName = "InteropTestsLocalCleartext.xctest"
-               BlueprintName = "InteropTestsLocalCleartext"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84421BE152B5000708E8"
-               BuildableName = "InteropTestsLocalCleartext.xctest"
-               BlueprintName = "InteropTestsLocalCleartext"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84421BE152B5000708E8"
-            BuildableName = "InteropTestsLocalCleartext.xctest"
-            BlueprintName = "InteropTestsLocalCleartext"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84421BE152B5000708E8"
-            BuildableName = "InteropTestsLocalCleartext.xctest"
-            BlueprintName = "InteropTestsLocalCleartext"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Test">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartextCFStream.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartextCFStream.xcscheme
deleted file mode 100644 (file)
index fe766de..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0920"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EC5E4302081856B000EF4AD"
-               BuildableName = "InteropTestsLocalCleartextCFStream.xctest"
-               BlueprintName = "InteropTestsLocalCleartextCFStream"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSLCFStream.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSLCFStream.xcscheme
deleted file mode 100644 (file)
index bd66327..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0920"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EC5E441208185CE000EF4AD"
-               BuildableName = "InteropTestsLocalSSLCFStream.xctest"
-               BlueprintName = "InteropTestsLocalSSLCFStream"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme
deleted file mode 100644 (file)
index 1b4c1f5..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0930"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Cronet"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EB2A2F42109284500EB4B69"
-               BuildableName = "InteropTestsMultipleChannels.xctest"
-               BlueprintName = "InteropTestsMultipleChannels"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Cronet"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteCFStream.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteCFStream.xcscheme
deleted file mode 100644 (file)
index 33a5ded..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0920"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Test"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EC5E420208177CC000EF4AD"
-               BuildableName = "InteropTestsRemoteCFStream.xctest"
-               BlueprintName = "InteropTestsRemoteCFStream"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme
deleted file mode 100644 (file)
index 1d21111..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0730"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
-               BuildableName = "InteropTestsRemoteWithCronet.xctest"
-               BlueprintName = "InteropTestsRemoteWithCronet"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Cronet"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
-               BuildableName = "InteropTestsRemoteWithCronet.xctest"
-               BlueprintName = "InteropTestsRemoteWithCronet"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-            <SkippedTests>
-               <Test
-                  Identifier = "InteropTests">
-               </Test>
-            </SkippedTests>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
-            BuildableName = "InteropTestsRemoteWithCronet.xctest"
-            BlueprintName = "InteropTestsRemoteWithCronet"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Cronet"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
-            BuildableName = "InteropTestsRemoteWithCronet.xctest"
-            BlueprintName = "InteropTestsRemoteWithCronet"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Cronet"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
-            BuildableName = "InteropTestsRemoteWithCronet.xctest"
-            BlueprintName = "InteropTestsRemoteWithCronet"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Cronet">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Cronet"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
index f84ac7f..fbd2d08 100644 (file)
@@ -51,7 +51,7 @@
       </AdditionalOptions>
    </TestAction>
    <LaunchAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Test"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme
deleted file mode 100644 (file)
index 3abc1d4..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0700"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "NO"
-            buildForArchiving = "NO"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84121BE15179000708E8"
-               BuildableName = "RxLibraryUnitTests.xctest"
-               BlueprintName = "RxLibraryUnitTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "63DC84121BE15179000708E8"
-               BuildableName = "RxLibraryUnitTests.xctest"
-               BlueprintName = "RxLibraryUnitTests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84121BE15179000708E8"
-            BuildableName = "RxLibraryUnitTests.xctest"
-            BlueprintName = "RxLibraryUnitTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "63DC84121BE15179000708E8"
-            BuildableName = "RxLibraryUnitTests.xctest"
-            BlueprintName = "RxLibraryUnitTests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme
deleted file mode 100644 (file)
index 77f567d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1010"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "635697C61B14FC11007A7283"
-               BuildableName = "libTests.a"
-               BlueprintName = "Tests"
-               ReferencedContainer = "container:Tests.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "635697C61B14FC11007A7283"
-            BuildableName = "libTests.a"
-            BlueprintName = "Tests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "635697C61B14FC11007A7283"
-            BuildableName = "libTests.a"
-            BlueprintName = "Tests"
-            ReferencedContainer = "container:Tests.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
index 3af3555..d20a9e5 100644 (file)
       </BuildActionEntries>
    </BuildAction>
    <TestAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Test"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
       shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
       </AdditionalOptions>
    </TestAction>
    <LaunchAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Test"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      language = ""
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
       ignoresPersistentStateOnLaunch = "NO"
similarity index 99%
rename from src/objective-c/tests/GRPCClientTests.m
rename to src/objective-c/tests/UnitTests/GRPCClientTests.m
index b361078..9416416 100644 (file)
@@ -33,7 +33,7 @@
 
 #include <netinet/in.h>
 
-#import "version.h"
+#import "../version.h"
 
 #define TEST_TIMEOUT 16
 
diff --git a/src/objective-c/tests/UnitTests/Info.plist b/src/objective-c/tests/UnitTests/Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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>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>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
 
 #import "../../GRPCClient/private/NSError+GRPC.h"
 
-@interface UnitTests : XCTestCase
+@interface NSErrorUnitTests : XCTestCase
 
 @end
 
-@implementation UnitTests
+@implementation NSErrorUnitTests
 
 - (void)testNSError {
   const char *kDetails = "test details";
similarity index 57%
rename from tools/internal_ci/macos/grpc_interop.sh
rename to src/objective-c/tests/examples_build_test.sh
index e290ed6..92ebaac 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2017 gRPC authors.
+# Copyright 2019 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
-source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+# This script is used after a release to verify the released pods are working appropriately
 
-tools/run_tests/run_interop_tests.py -l objc -s all --use_docker -t -j 1 || FAILED="true"
-
-tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+set -ex
 
-if [ "$FAILED" != "" ]
-then
-  exit 1
-fi
+SCHEME=HelloWorld EXAMPLE_PATH=examples/objective-c/helloworld ./build_one_example.sh
+SCHEME=RouteGuideClient EXAMPLE_PATH=examples/objective-c/route_guide ./build_one_example.sh
+SCHEME=AuthSample EXAMPLE_PATH=examples/objective-c/auth_sample ./build_one_example.sh
index 8c768cb..24185c5 100755 (executable)
@@ -43,98 +43,12 @@ XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^
 
 echo "TIME:  $(date)"
 
-# Retry the test for up to 3 times when return code is 65, due to Xcode issue:
-# http://www.openradar.me/29785686
-# The issue seems to be a connectivity issue to Xcode simulator so only retry
-# the first xcodebuild command
-retries=0
-while [ $retries -lt 3 ]; do
-  return_code=0
-  out=$(xcodebuild \
-        -workspace Tests.xcworkspace \
-        -scheme AllTests \
-        -destination name="iPhone 8" \
-        HOST_PORT_LOCALSSL=localhost:5051 \
-        HOST_PORT_LOCAL=localhost:5050 \
-        HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
-        test 2>&1 \
-        | egrep -v "$XCODEBUILD_FILTER" \
-        | egrep -v '^$' \
-        | egrep -v "(GPBDictionary|GPBArray)" - ) || return_code=$?
-  if [ $return_code == 65 ] && [[ $out == *"DTXProxyChannel error 1"* ]]; then
-    echo "$out"
-    echo "Failed with code 65 (DTXProxyChannel error 1); retry."
-    retries=$(($retries+1))
-  elif [ $return_code == 0 ]; then
-    echo "$out"
-    break
-  else
-    echo "$out"
-    echo "Failed with code $return_code."
-    exit 1
-  fi
-done
-if [ $retries == 3 ]; then
-  echo "Failed with code 65 for 3 times; abort."
-  exit 1
-fi
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme CoreCronetEnd2EndTests \
-    -destination name="iPhone 8" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme CoreCronetEnd2EndTests_Asan \
-    -destination name="iPhone 6" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme CoreCronetEnd2EndTests_Tsan \
-    -destination name="iPhone 6" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme CronetUnitTests \
-    -destination name="iPhone 8" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme InteropTestsRemoteWithCronet \
-    -destination name="iPhone 8" \
-    HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
 xcodebuild \
     -workspace Tests.xcworkspace \
-    -scheme InteropTestsRemoteCFStream \
+    -scheme InteropTests \
     -destination name="iPhone 8" \
+    HOST_PORT_LOCALSSL=localhost:5051 \
+    HOST_PORT_LOCAL=localhost:5050 \
     HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
     test \
     | egrep -v "$XCODEBUILD_FILTER" \
@@ -144,9 +58,11 @@ xcodebuild \
 echo "TIME:  $(date)"
 xcodebuild \
     -workspace Tests.xcworkspace \
-    -scheme InteropTestsLocalCleartextCFStream \
+    -scheme UnitTests \
     -destination name="iPhone 8" \
+    HOST_PORT_LOCALSSL=localhost:5051 \
     HOST_PORT_LOCAL=localhost:5050 \
+    HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
     test \
     | egrep -v "$XCODEBUILD_FILTER" \
     | egrep -v '^$' \
@@ -155,39 +71,9 @@ xcodebuild \
 echo "TIME:  $(date)"
 xcodebuild \
     -workspace Tests.xcworkspace \
-    -scheme InteropTestsLocalSSLCFStream \
+    -scheme CronetTests \
     -destination name="iPhone 8" \
     HOST_PORT_LOCALSSL=localhost:5051 \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme UnitTests \
-    -destination name="iPhone 8" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme ChannelTests \
-    -destination name="iPhone 8" \
-    test \
-    | egrep -v "$XCODEBUILD_FILTER" \
-    | egrep -v '^$' \
-    | egrep -v "(GPBDictionary|GPBArray)" -
-
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme APIv2Tests \
-    -destination name="iPhone 8" \
     HOST_PORT_LOCAL=localhost:5050 \
     HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
     test \
index 0aa72ca..37db5da 100644 (file)
@@ -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.21.3"
+#define GRPC_OBJC_VERSION_STRING @"1.22.0"
 #define GRPC_C_VERSION_STRING @"7.0.0"
index 5e9fa38..dde6152 100644 (file)
@@ -294,9 +294,9 @@ Run a local server serving the math services. Please see [Node][] for how to
 run an example server.
 
 ```sh
-$ cd grpc
+$ cd grpc/src/php/tests/generated_code
 $ npm install
-$ node src/node/test/math/math_server.js
+$ node math_server.js
 ```
 
 ### Run test client
index 48dfde5..ca1001b 100644 (file)
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Developement use only",
   "license": "Apache-2.0",
-  "version": "1.21.3",
+  "version": "1.22.0",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.3.0"
index c06bdea..860d38b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
 #include "completion_queue.h"
 #include "channel_credentials.h"
@@ -247,12 +248,12 @@ void create_and_add_channel_to_persistent_list(
       // If no channel can be deleted from the persistent map,
       // do not persist this one.
       create_channel(channel, target, args, creds);
-      php_printf("[Warning] The number of channel for the"
+      gpr_log(GPR_INFO, "[Warning] The number of channel for the"
                  " target %s is maxed out bounded.\n", target);
-      php_printf("[Warning] Target upper bound: %d. Current size: %d.\n",
+      gpr_log(GPR_INFO, "[Warning] Target upper bound: %d. Current size: %d.\n",
                  target_bound_status->upper_bound,
                  target_bound_status->current_count);
-      php_printf("[Warning] Target %s will not be persisted.\n", target);
+      gpr_log(GPR_INFO, "[Warning] Target %s will not be persisted.\n", target);
       return;
     }
   }
index d401a7d..d4e0bbc 100644 (file)
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.21.3"
+#define PHP_GRPC_VERSION "1.22.0"
 
 #endif /* VERSION_H */
index fe81e37..f33dbd4 100644 (file)
@@ -199,6 +199,13 @@ class BaseStub
      */
     private function _get_jwt_aud_uri($method)
     {
+        // TODO(jtattermusch): This is not the correct implementation
+        // of extracting JWT "aud" claim. We should rely on
+        // grpc_metadata_credentials_plugin which
+        // also provides the correct value of "aud" claim
+        // in the grpc_auth_metadata_context.service_url field.
+        // Trying to do the construction of "aud" field ourselves
+        // is bad.
         $last_slash_idx = strrpos($method, '/');
         if ($last_slash_idx === false) {
             throw new \InvalidArgumentException(
@@ -213,6 +220,12 @@ class BaseStub
             $hostname = $this->hostname;
         }
 
+        // Remove the port if it is 443
+        // See https://github.com/grpc/grpc/blob/07c9f7a36b2a0d34fcffebc85649cf3b8c339b5d/src/core/lib/security/transport/client_auth_filter.cc#L205
+        if ((strlen($hostname) > 4) && (substr($hostname, -4) === ":443")) {
+            $hostname = substr($hostname, 0, -4);
+        }
+
         return 'https://'.$hostname.$service_name;
     }
 
@@ -228,10 +241,10 @@ class BaseStub
     {
         $metadata_copy = [];
         foreach ($metadata as $key => $value) {
-            if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
+            if (!preg_match('/^[.A-Za-z\d_-]+$/', $key)) {
                 throw new \InvalidArgumentException(
                     'Metadata keys must be nonempty strings containing only '.
-                    'alphanumeric characters, hyphens and underscores'
+                    'alphanumeric characters, hyphens, underscores and dots'
                 );
             }
             $metadata_copy[strtolower($key)] = $value;
index c050a26..f7b4735 100644 (file)
@@ -71,6 +71,33 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase
         $call = self::$client->Div($div_arg, [' ' => 'abc123']);
     }
 
+    public function testMetadata()
+    {
+        $div_arg = new Math\DivArgs();
+        $call = self::$client->Div($div_arg, ['somekey' => ['abc123']]);
+    }
+
+    public function testMetadataKey()
+    {
+        $div_arg = new Math\DivArgs();
+        $call = self::$client->Div($div_arg, ['somekey_-1' => ['abc123']]);
+    }
+
+    public function testMetadataKeyWithDot()
+    {
+        $div_arg = new Math\DivArgs();
+        $call = self::$client->Div($div_arg, ['someKEY._-1' => ['abc123']]);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testMetadataInvalidKey()
+    {
+        $div_arg = new Math\DivArgs();
+        $call = self::$client->Div($div_arg, ['(somekey)' => ['abc123']]);
+    }
+
     public function testGetCallMetadata()
     {
         $div_arg = new Math\DivArgs();
@@ -81,6 +108,8 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase
     public function testTimeout()
     {
         $div_arg = new Math\DivArgs();
+        $div_arg->setDividend(7);
+        $div_arg->setDivisor(4);
         $call = self::$client->Div($div_arg, [], ['timeout' => 1]);
         list($response, $status) = $call->wait();
         $this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code);
diff --git a/src/php/tests/generated_code/math_server.js b/src/php/tests/generated_code/math_server.js
new file mode 100644 (file)
index 0000000..1492c93
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var PROTO_PATH = __dirname + '/../../../proto/math/math.proto';
+
+var grpc = require('grpc');
+var protoLoader = require('@grpc/proto-loader');
+var packageDefinition = protoLoader.loadSync(
+    PROTO_PATH,
+    {keepCase: true,
+     longs: String,
+     enums: String,
+     defaults: true,
+     oneofs: true
+    });
+var math_proto = grpc.loadPackageDefinition(packageDefinition).math;
+
+/**
+ * Implements the Div RPC method.
+ */
+function Div(call, callback) {
+  var divisor = call.request.divisor;
+  var dividend = call.request.dividend;
+  if (divisor == 0) {
+    callback({
+      code: grpc.status.INVALID_ARGUMENT,
+      details: 'Cannot divide by zero'
+    });
+  } else {
+    setTimeout(function () {
+      callback(null, {
+        quotient: Math.floor(dividend / divisor),
+        remainder: dividend % divisor
+      });
+    }, 1); // 1 millisecond, to make sure 1 microsecond timeout from test
+           // will hit. TODO: Consider fixing this.
+  }
+}
+
+/**
+ * Implements the Fib RPC method.
+ */
+function Fib(stream) {
+  var previous = 0, current = 1;
+  for (var i = 0; i < stream.request.limit; i++) {
+    stream.write({
+      num: current
+    });
+    var temp = current;
+    current += previous;
+    previous = temp;
+  }
+  stream.end();
+}
+
+/**
+ * Implements the Sum RPC method.
+ */
+function Sum(call, callback) {
+  var sum = 0;
+  call.on('data', function(data) {
+    sum += parseInt(data.num);
+  });
+  call.on('end', function() {
+    callback(null, {
+      num: sum
+    });
+  });
+}
+
+/**
+ * Implements the DivMany RPC method.
+ */
+function DivMany(stream) {
+  stream.on('data', function(div_args) {
+    var divisor = div_args.divisor;
+    var dividend = div_args.dividend;
+    if (divisor == 0) {
+      stream.emit('error', {
+        code: grpc.status.INVALID_ARGUMENT,
+        details: 'Cannot divide by zero'
+      });
+    } else {
+      stream.write({
+        quotient: Math.floor(dividend / divisor),
+        remainder: dividend % divisor
+      });
+    }
+  });
+  stream.on('end', function() {
+    stream.end();
+  });
+}
+
+
+/**
+ * Starts an RPC server that receives requests for the Math service at the
+ * sample server port
+ */
+function main() {
+  var server = new grpc.Server();
+  server.addService(math_proto.Math.service, {
+    Div: Div,
+    Fib: Fib,
+    Sum: Sum,
+    DivMany: DivMany,
+  });
+  server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
+  server.start();
+}
+
+main();
diff --git a/src/php/tests/generated_code/package.json b/src/php/tests/generated_code/package.json
new file mode 100644 (file)
index 0000000..5cc28be
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "grpc-examples",
+  "version": "0.1.0",
+  "dependencies": {
+    "@grpc/proto-loader": "^0.1.0",
+    "grpc": "^1.11.0"
+  }
+}
index 19cbf21..e475047 100755 (executable)
@@ -530,12 +530,7 @@ function _makeStub($args)
         throw new Exception('Missing argument: --test_case is required');
     }
 
-    if ($args['server_port'] === '443') {
-        $server_address = $args['server_host'];
-    } else {
-        $server_address = $args['server_host'].':'.$args['server_port'];
-    }
-
+    $server_address = $args['server_host'].':'.$args['server_port'];
     $test_case = $args['test_case'];
 
     $host_override = '';
index 727c99c..212f0f3 100644 (file)
@@ -18,11 +18,17 @@ load("//bazel:grpc_build_system.bzl", "grpc_proto_library", "grpc_package")
 load("@grpc_python_dependencies//:requirements.bzl", "requirement")
 load("//bazel:python_rules.bzl", "py_proto_library")
 
-grpc_package(name = "testing", visibility = "public")
+grpc_package(
+    name = "testing",
+    visibility = "public",
+)
 
 exports_files([
     "echo.proto",
     "echo_messages.proto",
+    "test.proto",
+    "empty.proto",
+    "messages.proto",
 ])
 
 grpc_proto_library(
@@ -50,9 +56,11 @@ grpc_proto_library(
 grpc_proto_library(
     name = "echo_proto",
     srcs = ["echo.proto"],
-    deps = ["echo_messages_proto",
-            "simple_messages_proto"],
     generate_mocks = True,
+    deps = [
+        "echo_messages_proto",
+        "simple_messages_proto",
+    ],
 )
 
 grpc_proto_library(
@@ -102,7 +110,7 @@ grpc_proto_library(
     name = "benchmark_service_proto",
     srcs = ["benchmark_service.proto"],
     deps = [
-      "messages_proto",
+        "messages_proto",
     ],
 )
 
@@ -110,7 +118,7 @@ grpc_proto_library(
     name = "report_qps_scenario_service_proto",
     srcs = ["report_qps_scenario_service.proto"],
     deps = [
-      "control_proto",
+        "control_proto",
     ],
 )
 
@@ -118,7 +126,7 @@ grpc_proto_library(
     name = "worker_service_proto",
     srcs = ["worker_service.proto"],
     deps = [
-      "control_proto",
+        "control_proto",
     ],
 )
 
@@ -134,7 +142,7 @@ grpc_proto_library(
     has_services = False,
     deps = [
         "//src/proto/grpc/core:stats_proto",
-    ]
+    ],
 )
 
 grpc_proto_library(
@@ -190,6 +198,5 @@ py_proto_library(
     name = "py_test_proto",
     deps = [
         ":test_proto_descriptor",
-    ]
+    ],
 )
-
index 07c9434..c7c6aa4 100644 (file)
@@ -1,8 +1,13 @@
 gRPC Python
 ===========
 
+|compat_check_pypi|
+
 Package for gRPC Python.
 
+.. |compat_check_pypi| image:: https://python-compatibility-tools.appspot.com/one_badge_image?package=grpcio
+   :target: https://python-compatibility-tools.appspot.com/one_badge_target?package=grpcio
+
 Supported Python Versions
 -------------------------
 Python >= 3.5
index 6175180..f0c198d 100644 (file)
@@ -584,6 +584,9 @@ class ChannelCredentials(object):
 class CallCredentials(object):
     """An encapsulation of the data required to assert an identity over a call.
 
+    A CallCredentials has to be used with secure Channel, otherwise the
+    metadata will not be transmitted to the server.
+
     A CallCredentials may be composed with ChannelCredentials to always assert
     identity for every call over that Channel.
 
@@ -682,7 +685,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             for the RPC.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -714,7 +718,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -746,7 +751,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -781,7 +787,8 @@ class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC. If None, the timeout is considered infinite.
           metadata: An optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -816,7 +823,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC. If None, the timeout is considered infinite.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -849,7 +857,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC. If None, the timeout is considered infinite.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -881,7 +890,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC. If None, the timeout is considered infinite.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
@@ -916,7 +926,8 @@ class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
             the RPC. If not specified, the timeout is considered infinite.
           metadata: Optional :term:`metadata` to be transmitted to the
             service-side of the RPC.
-          credentials: An optional CallCredentials for the RPC.
+          credentials: An optional CallCredentials for the RPC. Only valid for
+            secure Channel.
           wait_for_ready: This is an EXPERIMENTAL argument. An optional
             flag to enable wait for ready mechanism
           compression: An element of grpc.compression, e.g.
index 1272ee8..24f928e 100644 (file)
@@ -966,11 +966,6 @@ def _poll_connectivity(state, channel, initial_try_to_connect):
                         _spawn_delivery(state, callbacks)
 
 
-def _moot(state):
-    with state.lock:
-        del state.callbacks_and_connectivities[:]
-
-
 def _subscribe(state, callback, try_to_connect):
     with state.lock:
         if not state.callbacks_and_connectivities and not state.polling:
@@ -1066,15 +1061,21 @@ class Channel(grpc.Channel):
             self._channel, _channel_managed_call_management(self._call_state),
             _common.encode(method), request_serializer, response_deserializer)
 
+    def _unsubscribe_all(self):
+        state = self._connectivity_state
+        if state:
+            with state.lock:
+                del state.callbacks_and_connectivities[:]
+
     def _close(self):
+        self._unsubscribe_all()
         self._channel.close(cygrpc.StatusCode.cancelled, 'Channel closed!')
         cygrpc.fork_unregister_channel(self)
-        _moot(self._connectivity_state)
 
     def _close_on_fork(self):
+        self._unsubscribe_all()
         self._channel.close_on_fork(cygrpc.StatusCode.cancelled,
                                     'Channel closed due to fork')
-        _moot(self._connectivity_state)
 
     def __enter__(self):
         return self
@@ -1096,7 +1097,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.
-        # This prevent the failed-at-initializing object removal from failing.
-        # Though the __init__ failed, the removal will still trigger __del__.
-        if _moot is not None and hasattr(self, '_connectivity_state'):
-            _moot(self._connectivity_state)
+        try:
+            self._unsubscribe_all()
+        except:  # pylint: disable=bare-except
+            # Exceptions in __del__ are ignored by Python anyway, but they can
+            # keep spamming logs.  Just silence them.
+            pass
index af069ac..05892b3 100644 (file)
@@ -26,9 +26,9 @@ cdef int _get_metadata(
     grpc_credentials_plugin_metadata_cb cb, void *user_data,
     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
     size_t *num_creds_md, grpc_status_code *status,
-    const char **error_details) with gil
+    const char **error_details) except * with gil
 
-cdef void _destroy(void *state) with gil
+cdef void _destroy(void *state) except * with gil
 
 
 cdef class MetadataPluginCallCredentials(CallCredentials):
index 52ca92f..2ec1c0b 100644 (file)
@@ -42,7 +42,7 @@ cdef int _get_metadata(
     grpc_credentials_plugin_metadata_cb cb, void *user_data,
     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
     size_t *num_creds_md, grpc_status_code *status,
-    const char **error_details) with gil:
+    const char **error_details) except * with gil:
   cdef size_t metadata_count
   cdef grpc_metadata *c_metadata
   def callback(metadata, grpc_status_code status, bytes error_details):
@@ -57,7 +57,7 @@ cdef int _get_metadata(
   return 0  # Asynchronous return
 
 
-cdef void _destroy(void *state) with gil:
+cdef void _destroy(void *state) except * with gil:
   cpython.Py_DECREF(<object>state)
   grpc_shutdown_blocking()
 
index 057d077..a674c34 100644 (file)
@@ -546,8 +546,8 @@ cdef extern from "grpc/grpc_security.h":
         grpc_credentials_plugin_metadata_cb cb, void *user_data,
         grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
         size_t *num_creds_md, grpc_status_code *status,
-        const char **error_details)
-    void (*destroy)(void *state)
+        const char **error_details) except *
+    void (*destroy)(void *state) except *
     void *state
     const char *type
 
index 30fdf6a..59b3891 100644 (file)
@@ -44,12 +44,12 @@ cdef extern from "src/core/lib/iomgr/resolve_address_custom.h":
     pass
 
   struct grpc_custom_resolver_vtable:
-    grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res);
-    void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port);
+    grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res) except *
+    void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port) except *
 
   void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
                                     grpc_resolved_addresses* result,
-                                    grpc_error* error);
+                                    grpc_error* error)
 
 cdef extern from "src/core/lib/iomgr/tcp_custom.h":
   struct grpc_custom_socket:
@@ -67,25 +67,25 @@ cdef extern from "src/core/lib/iomgr/tcp_custom.h":
   ctypedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket)
 
   struct grpc_socket_vtable:
-      grpc_error* (*init)(grpc_custom_socket* socket, int domain);
+      grpc_error* (*init)(grpc_custom_socket* socket, int domain) except *
       void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
-                      size_t len, grpc_custom_connect_callback cb);
-      void (*destroy)(grpc_custom_socket* socket);
-      void (*shutdown)(grpc_custom_socket* socket);
-      void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb);
+                      size_t len, grpc_custom_connect_callback cb) except *
+      void (*destroy)(grpc_custom_socket* socket) except *
+      void (*shutdown)(grpc_custom_socket* socket) except *
+      void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb) except *
       void (*write)(grpc_custom_socket* socket, grpc_slice_buffer* slices,
-                    grpc_custom_write_callback cb);
+                    grpc_custom_write_callback cb) except *
       void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
-                   grpc_custom_read_callback cb);
+                   grpc_custom_read_callback cb) except *
       grpc_error* (*getpeername)(grpc_custom_socket* socket,
-                                 const grpc_sockaddr* addr, int* len);
+                                 const grpc_sockaddr* addr, int* len) except *
       grpc_error* (*getsockname)(grpc_custom_socket* socket,
-                             const grpc_sockaddr* addr, int* len);
+                             const grpc_sockaddr* addr, int* len) except *
       grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
-                          size_t len, int flags);
-      grpc_error* (*listen)(grpc_custom_socket* socket);
+                          size_t len, int flags) except *
+      grpc_error* (*listen)(grpc_custom_socket* socket) except *
       void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
-                     grpc_custom_accept_callback cb);
+                     grpc_custom_accept_callback cb) except *
 
 cdef extern from "src/core/lib/iomgr/timer_custom.h":
   struct grpc_custom_timer:
@@ -94,17 +94,17 @@ cdef extern from "src/core/lib/iomgr/timer_custom.h":
      # We don't care about the rest of the fields
 
   struct grpc_custom_timer_vtable:
-    void (*start)(grpc_custom_timer* t);
-    void (*stop)(grpc_custom_timer* t);
+    void (*start)(grpc_custom_timer* t) except *
+    void (*stop)(grpc_custom_timer* t) except *
 
-  void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+  void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error)
 
 cdef extern from "src/core/lib/iomgr/pollset_custom.h":
   struct grpc_custom_poller_vtable:
-    void (*init)()
-    void (*poll)(size_t timeout_ms)
-    void (*kick)()
-    void (*shutdown)()
+    void (*init)() except *
+    void (*poll)(size_t timeout_ms) except *
+    void (*kick)() except *
+    void (*shutdown)() except *
 
 cdef extern from "src/core/lib/iomgr/iomgr_custom.h":
   void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
index a1618d0..f82fca2 100644 (file)
@@ -56,7 +56,7 @@ cdef sockaddr_is_ipv4(const grpc_sockaddr* address, size_t length):
   c_addr.len = length
   return grpc_sockaddr_get_uri_scheme(&c_addr) == b'ipv4'
 
-cdef grpc_resolved_addresses* tuples_to_resolvaddr(tups):
+cdef grpc_resolved_addresses* tuples_to_resolvaddr(tups) except *:
   cdef grpc_resolved_addresses* addresses
   tups_set = set((tup[4][0], tup[4][1]) for tup in tups)
   addresses = <grpc_resolved_addresses*> malloc(sizeof(grpc_resolved_addresses))
@@ -84,7 +84,7 @@ cdef class SocketWrapper:
     self.c_buffer = NULL
     self.len = 0
 
-cdef grpc_error* socket_init(grpc_custom_socket* socket, int domain) with gil:
+cdef grpc_error* socket_init(grpc_custom_socket* socket, int domain) except * with gil:
   sw = SocketWrapper()
   sw.c_socket = socket
   sw.sockopts = []
@@ -112,7 +112,7 @@ def socket_connect_async(socket_wrapper, addr_tuple):
 
 cdef void socket_connect(grpc_custom_socket* socket, const grpc_sockaddr* addr,
                          size_t addr_len,
-                         grpc_custom_connect_callback cb) with gil:
+                         grpc_custom_connect_callback cb) except * with gil:
   py_socket = None
   socket_wrapper = <SocketWrapper>socket.impl
   socket_wrapper.connect_cb = cb
@@ -125,10 +125,10 @@ cdef void socket_connect(grpc_custom_socket* socket, const grpc_sockaddr* addr,
   socket_wrapper.socket = py_socket
   _spawn_greenlet(socket_connect_async, socket_wrapper, addr_tuple)
 
-cdef void socket_destroy(grpc_custom_socket* socket) with gil:
+cdef void socket_destroy(grpc_custom_socket* socket) except * with gil:
   cpython.Py_DECREF(<SocketWrapper>socket.impl)
 
-cdef void socket_shutdown(grpc_custom_socket* socket) with gil:
+cdef void socket_shutdown(grpc_custom_socket* socket) except * with gil:
   try:
     (<SocketWrapper>socket.impl).socket.shutdown(gevent_socket.SHUT_RDWR)
   except IOError as io_error:
@@ -136,7 +136,7 @@ cdef void socket_shutdown(grpc_custom_socket* socket) with gil:
       raise io_error
 
 cdef void socket_close(grpc_custom_socket* socket,
-                       grpc_custom_close_callback cb) with gil:
+                       grpc_custom_close_callback cb) except * with gil:
   socket_wrapper = (<SocketWrapper>socket.impl)
   if socket_wrapper.socket is not None:
     socket_wrapper.socket.close()
@@ -176,7 +176,7 @@ def socket_write_async(socket_wrapper, write_bytes):
   socket_write_async_cython(socket_wrapper, write_bytes)
 
 cdef void socket_write(grpc_custom_socket* socket, grpc_slice_buffer* buffer,
-                       grpc_custom_write_callback cb) with gil:
+                       grpc_custom_write_callback cb) except * with gil:
   cdef char* start
   sw = <SocketWrapper>socket.impl
   sw.write_cb = cb
@@ -204,7 +204,7 @@ def socket_read_async(socket_wrapper):
   socket_read_async_cython(socket_wrapper)
 
 cdef void socket_read(grpc_custom_socket* socket, char* buffer,
-                      size_t length, grpc_custom_read_callback cb) with gil:
+                      size_t length, grpc_custom_read_callback cb) except * with gil:
   sw = <SocketWrapper>socket.impl
   sw.read_cb = cb
   sw.c_buffer = buffer
@@ -213,7 +213,7 @@ cdef void socket_read(grpc_custom_socket* socket, char* buffer,
 
 cdef grpc_error* socket_getpeername(grpc_custom_socket* socket,
                                     const grpc_sockaddr* addr,
-                                    int* length) with gil:
+                                    int* length) except * with gil:
   cdef char* src_buf
   peer = (<SocketWrapper>socket.impl).socket.getpeername()
 
@@ -226,7 +226,7 @@ cdef grpc_error* socket_getpeername(grpc_custom_socket* socket,
 
 cdef grpc_error* socket_getsockname(grpc_custom_socket* socket,
                                     const grpc_sockaddr* addr,
-                                    int* length) with gil:
+                                    int* length) except * with gil:
   cdef char* src_buf
   cdef grpc_resolved_address c_addr
   if (<SocketWrapper>socket.impl).socket is None:
@@ -245,7 +245,7 @@ def applysockopts(s):
 
 cdef grpc_error* socket_bind(grpc_custom_socket* socket,
                              const grpc_sockaddr* addr,
-                             size_t len, int flags) with gil:
+                             size_t len, int flags) except * with gil:
   addr_tuple = sockaddr_to_tuple(addr, len)
   try:
     try:
@@ -262,7 +262,7 @@ cdef grpc_error* socket_bind(grpc_custom_socket* socket,
   else:
     return grpc_error_none()
 
-cdef grpc_error* socket_listen(grpc_custom_socket* socket) with gil:
+cdef grpc_error* socket_listen(grpc_custom_socket* socket) except * with gil:
   (<SocketWrapper>socket.impl).socket.listen(50)
   return grpc_error_none()
 
@@ -292,7 +292,7 @@ def socket_accept_async(s):
   accept_callback_cython(s)
 
 cdef void socket_accept(grpc_custom_socket* socket, grpc_custom_socket* client,
-                        grpc_custom_accept_callback cb) with gil:
+                        grpc_custom_accept_callback cb) except * with gil:
   sw = <SocketWrapper>socket.impl
   sw.accepting_socket = client
   sw.accept_cb = cb
@@ -322,7 +322,7 @@ cdef socket_resolve_async_cython(ResolveWrapper resolve_wrapper):
 def socket_resolve_async_python(resolve_wrapper):
   socket_resolve_async_cython(resolve_wrapper)
 
-cdef void socket_resolve_async(grpc_custom_resolver* r, char* host, char* port) with gil:
+cdef void socket_resolve_async(grpc_custom_resolver* r, char* host, char* port) except * with gil:
   rw = ResolveWrapper()
   rw.c_resolver = r
   rw.c_host = host
@@ -330,7 +330,7 @@ cdef void socket_resolve_async(grpc_custom_resolver* r, char* host, char* port)
   _spawn_greenlet(socket_resolve_async_python, rw)
 
 cdef grpc_error* socket_resolve(char* host, char* port,
-                                grpc_resolved_addresses** res) with gil:
+                                grpc_resolved_addresses** res) except * with gil:
     try:
       result = gevent_socket.getaddrinfo(host, port)
       res[0] = tuples_to_resolvaddr(result)
@@ -360,13 +360,13 @@ cdef class TimerWrapper:
     self.event.set()
     self.timer.stop()
 
-cdef void timer_start(grpc_custom_timer* t) with gil:
+cdef void timer_start(grpc_custom_timer* t) except * with gil:
   timer = TimerWrapper(t.timeout_ms / 1000.0)
   timer.c_timer = t
   t.timer = <void*>timer
   timer.start()
 
-cdef void timer_stop(grpc_custom_timer* t) with gil:
+cdef void timer_stop(grpc_custom_timer* t) except * with gil:
   time_wrapper = <object>t.timer
   time_wrapper.stop()
 
@@ -374,16 +374,16 @@ cdef void timer_stop(grpc_custom_timer* t) with gil:
 ### pollset implementation ###
 ###############################
 
-cdef void init_loop() with gil:
+cdef void init_loop() except * with gil:
   pass
 
-cdef void destroy_loop() with gil:
+cdef void destroy_loop() except * with gil:
   g_pool.join()
 
-cdef void kick_loop() with gil:
+cdef void kick_loop() except * with gil:
   g_event.set()
 
-cdef void run_loop(size_t timeout_ms) with gil:
+cdef void run_loop(size_t timeout_ms) except * with gil:
     timeout = timeout_ms / 1000.0
     if timeout_ms > 0:
       g_event.wait(timeout)
index ea4600f..b76cdd3 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.21.3"""
+__version__ = """1.22.0"""
index ad12bf4..7c5eca5 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index 73ecfb1..29ee7f8 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index c26d369..8bae17b 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index b434ba9..d1e46f6 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index 4516db4..583b2d9 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index 735c66a..c8ff0b0 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index ab2507f..2edf515 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index f8a3128..b1165a6 100644 (file)
@@ -124,6 +124,7 @@ grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
 grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
 grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import;
 grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
+grpc_ssl_credentials_create_ex_type grpc_ssl_credentials_create_ex_import;
 grpc_call_credentials_release_type grpc_call_credentials_release_import;
 grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import;
 grpc_composite_call_credentials_create_type grpc_composite_call_credentials_create_import;
@@ -393,6 +394,7 @@ void grpc_rb_load_imports(HMODULE library) {
   grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create");
   grpc_set_ssl_roots_override_callback_import = (grpc_set_ssl_roots_override_callback_type) GetProcAddress(library, "grpc_set_ssl_roots_override_callback");
   grpc_ssl_credentials_create_import = (grpc_ssl_credentials_create_type) GetProcAddress(library, "grpc_ssl_credentials_create");
+  grpc_ssl_credentials_create_ex_import = (grpc_ssl_credentials_create_ex_type) GetProcAddress(library, "grpc_ssl_credentials_create_ex");
   grpc_call_credentials_release_import = (grpc_call_credentials_release_type) GetProcAddress(library, "grpc_call_credentials_release");
   grpc_composite_channel_credentials_create_import = (grpc_composite_channel_credentials_create_type) GetProcAddress(library, "grpc_composite_channel_credentials_create");
   grpc_composite_call_credentials_create_import = (grpc_composite_call_credentials_create_type) GetProcAddress(library, "grpc_composite_call_credentials_create");
index 275ca6e..5809194 100644 (file)
@@ -347,6 +347,9 @@ extern grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_cal
 typedef grpc_channel_credentials*(*grpc_ssl_credentials_create_type)(const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, const verify_peer_options* verify_options, void* reserved);
 extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
 #define grpc_ssl_credentials_create grpc_ssl_credentials_create_import
+typedef grpc_channel_credentials*(*grpc_ssl_credentials_create_ex_type)(const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, const grpc_ssl_verify_peer_options* verify_options, void* reserved);
+extern grpc_ssl_credentials_create_ex_type grpc_ssl_credentials_create_ex_import;
+#define grpc_ssl_credentials_create_ex grpc_ssl_credentials_create_ex_import
 typedef void(*grpc_call_credentials_release_type)(grpc_call_credentials* creds);
 extern grpc_call_credentials_release_type grpc_call_credentials_release_import;
 #define grpc_call_credentials_release grpc_call_credentials_release_import
@@ -440,7 +443,7 @@ extern grpc_local_credentials_create_type grpc_local_credentials_create_import;
 typedef grpc_server_credentials*(*grpc_local_server_credentials_create_type)(grpc_local_connect_type type);
 extern grpc_local_server_credentials_create_type grpc_local_server_credentials_create_import;
 #define grpc_local_server_credentials_create grpc_local_server_credentials_create_import
-typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_create_type)();
+typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_create_type)(void);
 extern grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import;
 #define grpc_tls_credentials_options_create grpc_tls_credentials_options_create_import
 typedef int(*grpc_tls_credentials_options_set_cert_request_type_type)(grpc_tls_credentials_options* options, grpc_ssl_client_certificate_request_type type);
@@ -455,7 +458,7 @@ extern grpc_tls_credentials_options_set_credential_reload_config_type grpc_tls_c
 typedef int(*grpc_tls_credentials_options_set_server_authorization_check_config_type)(grpc_tls_credentials_options* options, grpc_tls_server_authorization_check_config* config);
 extern grpc_tls_credentials_options_set_server_authorization_check_config_type grpc_tls_credentials_options_set_server_authorization_check_config_import;
 #define grpc_tls_credentials_options_set_server_authorization_check_config grpc_tls_credentials_options_set_server_authorization_check_config_import
-typedef grpc_tls_key_materials_config*(*grpc_tls_key_materials_config_create_type)();
+typedef grpc_tls_key_materials_config*(*grpc_tls_key_materials_config_create_type)(void);
 extern grpc_tls_key_materials_config_create_type grpc_tls_key_materials_config_create_import;
 #define grpc_tls_key_materials_config_create grpc_tls_key_materials_config_create_import
 typedef int(*grpc_tls_key_materials_config_set_key_materials_type)(grpc_tls_key_materials_config* config, const char* pem_root_certs, const grpc_ssl_pem_key_cert_pair** pem_key_cert_pairs, size_t num_key_cert_pairs);
index 55b26e4..c80fb62 100644 (file)
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.21.3'
+  VERSION = '1.22.0'
 end
index 4effc70..f6c3dfa 100644 (file)
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.21.3'
+    VERSION = '1.22.0'
   end
 end
index 4057da4..d42d2c6 100644 (file)
       set(_gRPC_PLATFORM_LINUX ON)
     elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Darwin")
       set(_gRPC_PLATFORM_MAC ON)
+    elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "iOS")
+      set(_gRPC_PLATFORM_IOS ON)
     elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Android")
       set(_gRPC_PLATFORM_ANDROID ON)
     else()
     endif()
   endif()
 
-  if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
+  if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
     # C core has C++ source code, but should not depend on libstc++ (for better portability).
     # We need to use a few tricks to convince cmake to do that.
     # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc
     set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS}</%text> -std=c++11")
   endif()
 
-  if(_gRPC_PLATFORM_MAC)
+  if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m pthread)
   elseif(_gRPC_PLATFORM_ANDROID)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m)
   % for lib in libs:
   % if lib.build in ["all", "protoc", "tool", "test", "private"] and not lib.boringssl:
   % if not lib.get('build_system', []) or 'cmake' in lib.get('build_system', []):
-  % if not lib.name in ['ares', 'benchmark', 'z']:  # we build these using CMake instead
+  % if not lib.name in ['ares', 'benchmark', 'upb', 'z']:  # we build these using CMake instead
   % if lib.build in ["test", "private"]:
   if (gRPC_BUILD_TESTS)
   ${cc_library(lib)}
index d2b54a9..12862c8 100644 (file)
@@ -15,7 +15,7 @@
     s.description   = 'Send RPCs from Ruby using GRPC'
     s.license       = 'Apache-2.0'
 
-    s.required_ruby_version = '>= 2.0.0'
+    s.required_ruby_version = '>= 2.3.0'
 
     s.files = %w( Makefile .yardopts )
     s.files += %w( etc/roots.pem )
@@ -31,7 +31,7 @@
     s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
-    s.add_dependency 'google-protobuf', '~> 3.7'
+    s.add_dependency 'google-protobuf', '~> 3.8'
     s.add_dependency 'googleapis-common-protos-types', '~> 1.0'
 
     s.add_development_dependency 'bundler',            '~> 1.9'
index 741f9b7..b2335ac 100644 (file)
     s.preserve_paths = plugin
 
     # Restrict the protoc version to the one supported by this plugin.
-    s.dependency '!ProtoCompiler', '3.7.0'
+    s.dependency '!ProtoCompiler', '3.8.0'
     # For the Protobuf dependency not to complain:
     s.ios.deployment_target = '7.0'
     s.osx.deployment_target = '10.9'
index d40ba20..91fa1d9 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <grpc/support/log.h>
 
-#include "test/core/util/debugger_macros.h"
 
 static bool g_pre_init_called = false;
 
@@ -39,7 +38,6 @@ extern void ${test}_pre_init(void);
 void grpc_end2end_tests_pre_init(void) {
   GPR_ASSERT(!g_pre_init_called);
   g_pre_init_called = true;
-  grpc_summon_debugger_macros();
 % for test in tests:
   ${test}_pre_init();
 % endfor
index 8888e93..2729360 100644 (file)
@@ -1,7 +1,13 @@
 #========================
 # Bazel installation
 
+# Must be in sync with tools/bazel
+ENV BAZEL_VERSION 0.24.1
+
+# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper.
+ENV DISABLE_BAZEL_WRAPPER 1
+
 RUN apt-get update && apt-get install -y wget && apt-get clean
-RUN wget https://github.com/bazelbuild/bazel/releases/download/0.23.2/bazel-0.23.2-installer-linux-x86_64.sh && ${'\\'}
-  bash ./bazel-0.23.2-installer-linux-x86_64.sh && ${'\\'}
-  rm bazel-0.23.2-installer-linux-x86_64.sh
+RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && ${'\\'}
+  bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && ${'\\'}
+  rm bazel-$BAZEL_VERSION-installer-linux-x86_64.sh
index 05ad947..acf1257 100644 (file)
@@ -38,8 +38,5 @@
   then
     ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet
   fi
-  
-  ./build/get-grpc.sh
 
-  cd testassets/InteropTestsWebsite
-  dotnet build --configuration Debug
+  dotnet build --configuration Debug Grpc.DotNet.sln
 
 <%include file="../../debian_jessie_header.include"/>
 
-<%include file="java_deps.include"/>
+RUN echo "deb http://archive.debian.org/debian/ jessie-backports main contrib non-free" > /etc/apt/sources.list.d/jessie-backports.list && ${'\\'}
+    echo 'Acquire::Check-Valid-Until no;' > /etc/apt/apt.conf.d/99no-check-valid-until && ${'\\'}
+    apt-get update && ${'\\'}
+    apt-get install -y --no-install-recommends -t jessie-backports openjdk-8-jdk-headless && ${'\\'}
+    apt-get clean
 
 # Define the default command.
 CMD ["bash"]
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java/java_deps.include b/templates/tools/dockerfile/interoptest/grpc_interop_java/java_deps.include
deleted file mode 100644 (file)
index 40d70e0..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# Install JDK 8 and Git
-#
-RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && ${'\\'}
-  echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && ${'\\'}
-  echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && ${'\\'}
-  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
-
-RUN apt-get update && apt-get -y install ${'\\'}
-      git ${'\\'}
-      libapr1 ${'\\'}
-      oracle-java8-installer ${'\\'}
-      && ${'\\'}
-    apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
-
-ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-ENV PATH $PATH:$JAVA_HOME/bin
-
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile.template
deleted file mode 100644 (file)
index 8eaa9a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%YAML 1.2
---- |
-  <%include file="Dockerfile.include"/>
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh.template
deleted file mode 100644 (file)
index db5d40d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%YAML 1.2
---- |
-  <%include file="../../java_build_interop.sh.include"/>  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/java_deps.include b/templates/tools/dockerfile/interoptest/grpc_interop_java_oracle8/java_deps.include
deleted file mode 100644 (file)
index c05b564..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Install JDK 8
-#
-RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && ${'\\'}
-  echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && ${'\\'}
-  echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && ${'\\'}
-  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && ${'\\'}
-  apt-get update && apt-get -y install oracle-java8-installer && ${'\\'}
-  apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
-
-ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-ENV PATH $PATH:$JAVA_HOME/bin
-
diff --git a/templates/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile.template
new file mode 100644 (file)
index 0000000..8f2585a
--- /dev/null
@@ -0,0 +1,28 @@
+
+%YAML 1.2
+--- |
+  # Copyright 2019 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.
+
+  <%include file="../../python_stretch.include"/>
+  RUN apt-get install -y jq zlib1g-dev libssl-dev
+
+  COPY get_cpython.sh /tmp
+  RUN apt-get install -y jq build-essential libffi-dev && ${'\\'}
+    chmod +x /tmp/get_cpython.sh && ${'\\'}
+    /tmp/get_cpython.sh && ${'\\'}
+    rm /tmp/get_cpython.sh
+
+  RUN python3.8 -m ensurepip && ${'\\'}
+      python3.8 -m pip install coverage
index 6a40b4e..a4f3e4a 100755 (executable)
@@ -17,6 +17,7 @@
 """Generates the appropriate build.json data for all the bad_client tests."""
 
 
+from __future__ import print_function
 import collections
 import yaml
 
@@ -45,7 +46,7 @@ def main():
           {
             'name': 'bad_client_test',
             'build': 'private',
-            'language': 'c',
+            'language': 'c++',
             'src': [
               'test/core/bad_client/bad_client.cc'
             ],
@@ -64,7 +65,7 @@ def main():
               'name': '%s_bad_client_test' % t,
               'cpu_cost': BAD_CLIENT_TESTS[t].cpu_cost,
               'build': 'test',
-              'language': 'c',
+              'language': 'c++',
               'secure': 'no',
               'src': ['test/core/bad_client/tests/%s.cc' % t],
               'vs_proj_dir': 'test',
@@ -77,7 +78,7 @@ def main():
               ]
           }
       for t in sorted(BAD_CLIENT_TESTS.keys())]}
-  print yaml.dump(json)
+  print(yaml.dump(json))
 
 
 if __name__ == '__main__':
index 2769d5c..da372dd 100755 (executable)
@@ -42,6 +42,7 @@ def grpc_bad_client_tests():
       name = 'bad_client_test',
       srcs = ['bad_client.cc'],
       hdrs = ['bad_client.h'],
+      language = "C++",
       deps = ['//test/core/util:grpc_test_util', '//:grpc', '//:gpr', '//test/core/end2end:cq_verifier']
   )
   for t, topt in BAD_CLIENT_TESTS.items():
@@ -49,5 +50,8 @@ def grpc_bad_client_tests():
         name = '%s_bad_client_test' % t,
         srcs = ['tests/%s.cc' % t],
         deps = [':bad_client_test'],
+        external_deps = [
+          "gtest",
+        ],        
     )
 
index 9e0cf3f..e58166c 100644 (file)
  *
  */
 
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <grpc/support/string_util.h>
 #include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
 
-#define PFX_STR                      \
-  "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
-  "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
-
 static void verifier(grpc_server* server, grpc_completion_queue* cq,
                      void* registered_method) {
   while (grpc_server_has_open_connections(server)) {
@@ -32,15 +33,33 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq,
   }
 }
 
+#define APPEND_BUFFER(string, to_append) \
+  ((string).append((to_append), sizeof(to_append) - 1))
+
+namespace {
+TEST(UnknownFrameType, Test) {
+  /* test that all invalid/unknown frame types are handled */
+  for (int i = 10; i <= 255; i++) {
+    std::string unknown_frame_string;
+    APPEND_BUFFER(unknown_frame_string, "\x00\x00\x00");
+    char frame_type = static_cast<char>(i);
+    unknown_frame_string.append(&frame_type, 1);
+    APPEND_BUFFER(unknown_frame_string, "\x00\x00\x00\x00\x01");
+    grpc_bad_client_arg args[2];
+    args[0] = connection_preface_arg;
+    args[1].client_validator = nullptr;
+    args[1].client_payload = unknown_frame_string.c_str();
+    args[1].client_payload_length = unknown_frame_string.size();
+    grpc_run_bad_client_test(verifier, args, 2, GRPC_BAD_CLIENT_DISCONNECT);
+  }
+}
+}  // namespace
+
 int main(int argc, char** argv) {
   grpc_init();
   grpc::testing::TestEnvironment env(argc, argv);
-
-  /* test adding prioritization data */
-  GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr,
-                           PFX_STR "\x00\x00\x00\x88\x00\x00\x00\x00\x01",
-                           GRPC_BAD_CLIENT_DISCONNECT);
-
+  ::testing::InitGoogleTest(&argc, argv);
+  int retval = RUN_ALL_TESTS();
   grpc_shutdown();
-  return 0;
+  return retval;
 }
index b3c0b36..5ac7f08 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/channel/channelz.h"
@@ -174,7 +175,7 @@ TEST(ChannelTracerTest, ComplexTest) {
   AddSimpleTrace(&tracer);
   ChannelFixture channel1(kEventListMemoryLimit);
   RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
-      channel1.channel(), kEventListMemoryLimit, true);
+      UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
   ChannelNodePeer sc1_peer(sc1.get());
   tracer.AddTraceEventWithReference(
       ChannelTrace::Severity::Info,
@@ -193,7 +194,7 @@ TEST(ChannelTracerTest, ComplexTest) {
   ValidateChannelTrace(&tracer, 5);
   ChannelFixture channel2(kEventListMemoryLimit);
   RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
-      channel2.channel(), kEventListMemoryLimit, true);
+      UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
   tracer.AddTraceEventWithReference(
       ChannelTrace::Severity::Info,
       grpc_slice_from_static_string("LB channel two created"), sc2);
@@ -222,7 +223,7 @@ TEST(ChannelTracerTest, TestNesting) {
   ValidateChannelTrace(&tracer, 2);
   ChannelFixture channel1(kEventListMemoryLimit);
   RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
-      channel1.channel(), kEventListMemoryLimit, true);
+      UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
   ChannelNodePeer sc1_peer(sc1.get());
   tracer.AddTraceEventWithReference(
       ChannelTrace::Severity::Info,
@@ -231,7 +232,7 @@ TEST(ChannelTracerTest, TestNesting) {
   AddSimpleTrace(sc1_peer.trace());
   ChannelFixture channel2(kEventListMemoryLimit);
   RefCountedPtr<ChannelNode> conn1 = MakeRefCounted<ChannelNode>(
-      channel2.channel(), kEventListMemoryLimit, true);
+      UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
   ChannelNodePeer conn1_peer(conn1.get());
   // nesting one level deeper.
   sc1_peer.trace()->AddTraceEventWithReference(
@@ -245,7 +246,7 @@ TEST(ChannelTracerTest, TestNesting) {
   ValidateChannelTrace(conn1_peer.trace(), 1);
   ChannelFixture channel3(kEventListMemoryLimit);
   RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
-      channel3.channel(), kEventListMemoryLimit, true);
+      UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
   tracer.AddTraceEventWithReference(
       ChannelTrace::Severity::Info,
       grpc_slice_from_static_string("subchannel two created"), sc2);
index 31841f9..deb85d8 100644 (file)
@@ -43,16 +43,6 @@ namespace grpc_core {
 namespace channelz {
 namespace testing {
 
-class ChannelzRegistryPeer {
- public:
-  const InlinedVector<BaseNode*, 20>* entities() {
-    return &ChannelzRegistry::Default()->entities_;
-  }
-  int num_empty_slots() {
-    return ChannelzRegistry::Default()->num_empty_slots_;
-  }
-};
-
 class ChannelzRegistryTest : public ::testing::Test {
  protected:
   // ensure we always have a fresh registry for tests.
@@ -62,8 +52,8 @@ class ChannelzRegistryTest : public ::testing::Test {
 };
 
 TEST_F(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
-  UniquePtr<BaseNode> channelz_channel =
-      MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
+  RefCountedPtr<BaseNode> channelz_channel =
+      MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
   intptr_t uuid = channelz_channel->uuid();
   EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if "
                         "reserved according to "
@@ -72,11 +62,11 @@ TEST_F(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
 }
 
 TEST_F(ChannelzRegistryTest, UuidsAreIncreasing) {
-  std::vector<UniquePtr<BaseNode>> channelz_channels;
+  std::vector<RefCountedPtr<BaseNode>> channelz_channels;
   channelz_channels.reserve(10);
   for (int i = 0; i < 10; ++i) {
     channelz_channels.push_back(
-        MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+        MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
   }
   for (size_t i = 1; i < channelz_channels.size(); ++i) {
     EXPECT_LT(channelz_channels[i - 1]->uuid(), channelz_channels[i]->uuid())
@@ -85,108 +75,73 @@ TEST_F(ChannelzRegistryTest, UuidsAreIncreasing) {
 }
 
 TEST_F(ChannelzRegistryTest, RegisterGetTest) {
-  UniquePtr<BaseNode> channelz_channel =
-      MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
-  BaseNode* retrieved = ChannelzRegistry::Get(channelz_channel->uuid());
-  EXPECT_EQ(channelz_channel.get(), retrieved);
+  RefCountedPtr<BaseNode> channelz_channel =
+      MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
+  RefCountedPtr<BaseNode> retrieved =
+      ChannelzRegistry::Get(channelz_channel->uuid());
+  EXPECT_EQ(channelz_channel, retrieved);
 }
 
 TEST_F(ChannelzRegistryTest, RegisterManyItems) {
-  std::vector<UniquePtr<BaseNode>> channelz_channels;
+  std::vector<RefCountedPtr<BaseNode>> channelz_channels;
   for (int i = 0; i < 100; i++) {
     channelz_channels.push_back(
-        MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-    BaseNode* retrieved = ChannelzRegistry::Get(channelz_channels[i]->uuid());
-    EXPECT_EQ(channelz_channels[i].get(), retrieved);
+        MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+    RefCountedPtr<BaseNode> retrieved =
+        ChannelzRegistry::Get(channelz_channels[i]->uuid());
+    EXPECT_EQ(channelz_channels[i], retrieved);
   }
 }
 
 TEST_F(ChannelzRegistryTest, NullIfNotPresentTest) {
-  UniquePtr<BaseNode> channelz_channel =
-      MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
+  RefCountedPtr<BaseNode> channelz_channel =
+      MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
   // try to pull out a uuid that does not exist.
-  BaseNode* nonexistant = ChannelzRegistry::Get(channelz_channel->uuid() + 1);
+  RefCountedPtr<BaseNode> nonexistant =
+      ChannelzRegistry::Get(channelz_channel->uuid() + 1);
   EXPECT_EQ(nonexistant, nullptr);
-  BaseNode* retrieved = ChannelzRegistry::Get(channelz_channel->uuid());
-  EXPECT_EQ(channelz_channel.get(), retrieved);
-}
-
-TEST_F(ChannelzRegistryTest, TestCompaction) {
-  const int kLoopIterations = 300;
-  // These channels that will stay in the registry for the duration of the test.
-  std::vector<UniquePtr<BaseNode>> even_channels;
-  even_channels.reserve(kLoopIterations);
-  {
-    // The channels will unregister themselves at the end of the for block.
-    std::vector<UniquePtr<BaseNode>> odd_channels;
-    odd_channels.reserve(kLoopIterations);
-    for (int i = 0; i < kLoopIterations; i++) {
-      even_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-      odd_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-    }
-  }
-  // without compaction, there would be exactly kLoopIterations empty slots at
-  // this point. However, one of the unregisters should have triggered
-  // compaction.
-  ChannelzRegistryPeer peer;
-  EXPECT_LT(peer.num_empty_slots(), kLoopIterations);
+  RefCountedPtr<BaseNode> retrieved =
+      ChannelzRegistry::Get(channelz_channel->uuid());
+  EXPECT_EQ(channelz_channel, retrieved);
 }
 
-TEST_F(ChannelzRegistryTest, TestGetAfterCompaction) {
+TEST_F(ChannelzRegistryTest, TestUnregistration) {
   const int kLoopIterations = 100;
-  // These channels that will stay in the registry for the duration of the test.
-  std::vector<UniquePtr<BaseNode>> even_channels;
+  // These channels will stay in the registry for the duration of the test.
+  std::vector<RefCountedPtr<BaseNode>> even_channels;
   even_channels.reserve(kLoopIterations);
   std::vector<intptr_t> odd_uuids;
   odd_uuids.reserve(kLoopIterations);
   {
-    // The channels will unregister themselves at the end of the for block.
-    std::vector<UniquePtr<BaseNode>> odd_channels;
+    // These channels will unregister themselves at the end of this block.
+    std::vector<RefCountedPtr<BaseNode>> odd_channels;
     odd_channels.reserve(kLoopIterations);
     for (int i = 0; i < kLoopIterations; i++) {
       even_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+          MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
       odd_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+          MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
       odd_uuids.push_back(odd_channels[i]->uuid());
     }
   }
+  // Check that the even channels are present and the odd channels are not.
   for (int i = 0; i < kLoopIterations; i++) {
-    BaseNode* retrieved = ChannelzRegistry::Get(even_channels[i]->uuid());
-    EXPECT_EQ(even_channels[i].get(), retrieved);
+    RefCountedPtr<BaseNode> retrieved =
+        ChannelzRegistry::Get(even_channels[i]->uuid());
+    EXPECT_EQ(even_channels[i], retrieved);
     retrieved = ChannelzRegistry::Get(odd_uuids[i]);
     EXPECT_EQ(retrieved, nullptr);
   }
-}
-
-TEST_F(ChannelzRegistryTest, TestAddAfterCompaction) {
-  const int kLoopIterations = 100;
-  // These channels that will stay in the registry for the duration of the test.
-  std::vector<UniquePtr<BaseNode>> even_channels;
-  even_channels.reserve(kLoopIterations);
-  std::vector<intptr_t> odd_uuids;
-  odd_uuids.reserve(kLoopIterations);
-  {
-    // The channels will unregister themselves at the end of the for block.
-    std::vector<UniquePtr<BaseNode>> odd_channels;
-    odd_channels.reserve(kLoopIterations);
-    for (int i = 0; i < kLoopIterations; i++) {
-      even_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-      odd_channels.push_back(
-          MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-      odd_uuids.push_back(odd_channels[i]->uuid());
-    }
-  }
-  std::vector<UniquePtr<BaseNode>> more_channels;
+  // Add more channels and verify that they get added correctly, to make
+  // sure that the unregistration didn't leave the registry in a weird state.
+  std::vector<RefCountedPtr<BaseNode>> more_channels;
   more_channels.reserve(kLoopIterations);
   for (int i = 0; i < kLoopIterations; i++) {
     more_channels.push_back(
-        MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
-    BaseNode* retrieved = ChannelzRegistry::Get(more_channels[i]->uuid());
-    EXPECT_EQ(more_channels[i].get(), retrieved);
+        MakeRefCounted<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+    RefCountedPtr<BaseNode> retrieved =
+        ChannelzRegistry::Get(more_channels[i]->uuid());
+    EXPECT_EQ(more_channels[i], retrieved);
   }
 }
 
index abd1601..7c55f9f 100644 (file)
@@ -486,8 +486,7 @@ TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) {
   (void)channels;  // suppress unused variable error
   // create an internal channel
   grpc_arg client_a[2];
-  client_a[0] = grpc_channel_arg_integer_create(
-      const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true);
+  client_a[0] = grpc_core::channelz::MakeParentUuidArg(1);
   client_a[1] = grpc_channel_arg_integer_create(
       const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
   grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
index 9734304..919441d 100644 (file)
@@ -31,9 +31,9 @@
 namespace grpc_core {
 namespace testing {
 
-class TestParsedObject1 : public ServiceConfig::ParsedConfig {
+class TestParsedConfig1 : public ServiceConfig::ParsedConfig {
  public:
-  TestParsedObject1(int value) : value_(value) {}
+  TestParsedConfig1(int value) : value_(value) {}
 
   int value() const { return value_; }
 
@@ -61,7 +61,7 @@ class TestParser1 : public ServiceConfig::Parser {
           return nullptr;
         }
         return UniquePtr<ServiceConfig::ParsedConfig>(
-            New<TestParsedObject1>(value));
+            New<TestParsedConfig1>(value));
       }
     }
     return nullptr;
@@ -99,7 +99,7 @@ class TestParser2 : public ServiceConfig::Parser {
           return nullptr;
         }
         return UniquePtr<ServiceConfig::ParsedConfig>(
-            New<TestParsedObject1>(value));
+            New<TestParsedConfig1>(value));
       }
     }
     return nullptr;
@@ -216,10 +216,10 @@ TEST_F(ServiceConfigTest, Parser1BasicTest1) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  EXPECT_TRUE((static_cast<TestParsedObject1*>(
-                   svc_cfg->GetParsedGlobalServiceConfigObject(0)))
-                  ->value() == 5);
-  EXPECT_TRUE(svc_cfg->GetMethodServiceConfigObjectsVector(
+  EXPECT_TRUE(
+      (static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
+          ->value() == 5);
+  EXPECT_TRUE(svc_cfg->GetMethodParsedConfigVector(
                   grpc_slice_from_static_string("/TestServ/TestMethod")) ==
               nullptr);
 }
@@ -229,9 +229,9 @@ TEST_F(ServiceConfigTest, Parser1BasicTest2) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  EXPECT_TRUE((static_cast<TestParsedObject1*>(
-                   svc_cfg->GetParsedGlobalServiceConfigObject(0)))
-                  ->value() == 1000);
+  EXPECT_TRUE(
+      (static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
+          ->value() == 1000);
 }
 
 TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
@@ -267,11 +267,11 @@ TEST_F(ServiceConfigTest, Parser2BasicTest) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector(
+  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   EXPECT_TRUE(vector_ptr != nullptr);
-  auto parsed_object = ((*vector_ptr)[1]).get();
-  EXPECT_TRUE(static_cast<TestParsedObject1*>(parsed_object)->value() == 5);
+  auto parsed_config = ((*vector_ptr)[1]).get();
+  EXPECT_TRUE(static_cast<TestParsedConfig1*>(parsed_config)->value() == 5);
 }
 
 TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
@@ -371,10 +371,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  auto lb_config = parsed_object->parsed_lb_config();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  auto lb_config = parsed_config->parsed_lb_config();
   EXPECT_TRUE(strcmp(lb_config->name(), "pick_first") == 0);
 }
 
@@ -384,10 +384,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  auto parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  auto lb_config = parsed_object->parsed_lb_config();
+  auto parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  auto lb_config = parsed_config->parsed_lb_config();
   EXPECT_TRUE(strcmp(lb_config->name(), "round_robin") == 0);
 }
 
@@ -398,10 +398,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  auto lb_config = parsed_object->parsed_lb_config();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  auto lb_config = parsed_config->parsed_lb_config();
   EXPECT_TRUE(strcmp(lb_config->name(), "grpclb") == 0);
 }
 
@@ -417,10 +417,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  auto lb_config = parsed_object->parsed_lb_config();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  auto lb_config = parsed_config->parsed_lb_config();
   EXPECT_TRUE(strcmp(lb_config->name(), "xds_experimental") == 0);
 }
 
@@ -484,10 +484,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  const auto* lb_policy = parsed_object->parsed_deprecated_lb_policy();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy();
   ASSERT_TRUE(lb_policy != nullptr);
   EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0);
 }
@@ -498,10 +498,10 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  const auto* lb_policy = parsed_object->parsed_deprecated_lb_policy();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy();
   ASSERT_TRUE(lb_policy != nullptr);
   EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0);
 }
@@ -549,10 +549,10 @@ TEST_F(ClientChannelParserTest, ValidRetryThrottling) {
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  const auto retryThrottling = parsed_object->retry_throttling();
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  const auto retryThrottling = parsed_config->retry_throttling();
   ASSERT_TRUE(retryThrottling.has_value());
   EXPECT_EQ(retryThrottling.value().max_milli_tokens, 2000);
   EXPECT_EQ(retryThrottling.value().milli_token_ratio, 1000);
@@ -633,12 +633,12 @@ TEST_F(ClientChannelParserTest, ValidTimeout) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector(
+  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   EXPECT_TRUE(vector_ptr != nullptr);
-  auto parsed_object = ((*vector_ptr)[0]).get();
-  EXPECT_EQ((static_cast<grpc_core::internal::ClientChannelMethodParsedObject*>(
-                 parsed_object))
+  auto parsed_config = ((*vector_ptr)[0]).get();
+  EXPECT_EQ((static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
+                 parsed_config))
                 ->timeout(),
             5000);
 }
@@ -680,18 +680,18 @@ TEST_F(ClientChannelParserTest, ValidWaitForReady) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector(
+  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   EXPECT_TRUE(vector_ptr != nullptr);
-  auto parsed_object = ((*vector_ptr)[0]).get();
+  auto parsed_config = ((*vector_ptr)[0]).get();
   EXPECT_TRUE(
-      (static_cast<grpc_core::internal::ClientChannelMethodParsedObject*>(
-           parsed_object))
+      (static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
+           parsed_config))
           ->wait_for_ready()
           .has_value());
   EXPECT_TRUE(
-      (static_cast<grpc_core::internal::ClientChannelMethodParsedObject*>(
-           parsed_object))
+      (static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
+           parsed_config))
           ->wait_for_ready()
           .value());
 }
@@ -740,18 +740,18 @@ TEST_F(ClientChannelParserTest, ValidRetryPolicy) {
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector(
+  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   EXPECT_TRUE(vector_ptr != nullptr);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelMethodParsedObject*>(
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
           ((*vector_ptr)[0]).get());
-  EXPECT_TRUE(parsed_object->retry_policy() != nullptr);
-  EXPECT_EQ(parsed_object->retry_policy()->max_attempts, 3);
-  EXPECT_EQ(parsed_object->retry_policy()->initial_backoff, 1000);
-  EXPECT_EQ(parsed_object->retry_policy()->max_backoff, 120000);
-  EXPECT_EQ(parsed_object->retry_policy()->backoff_multiplier, 1.6f);
-  EXPECT_TRUE(parsed_object->retry_policy()->retryable_status_codes.Contains(
+  EXPECT_TRUE(parsed_config->retry_policy() != nullptr);
+  EXPECT_EQ(parsed_config->retry_policy()->max_attempts, 3);
+  EXPECT_EQ(parsed_config->retry_policy()->initial_backoff, 1000);
+  EXPECT_EQ(parsed_config->retry_policy()->max_backoff, 120000);
+  EXPECT_EQ(parsed_config->retry_policy()->backoff_multiplier, 1.6f);
+  EXPECT_TRUE(parsed_config->retry_policy()->retryable_status_codes.Contains(
       GRPC_STATUS_ABORTED));
 }
 
@@ -915,11 +915,11 @@ TEST_F(ClientChannelParserTest, ValidHealthCheck) {
   grpc_error* error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* parsed_object =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedObject*>(
-          svc_cfg->GetParsedGlobalServiceConfigObject(0));
-  ASSERT_TRUE(parsed_object != nullptr);
-  EXPECT_EQ(strcmp(parsed_object->health_check_service_name(),
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  ASSERT_TRUE(parsed_config != nullptr);
+  EXPECT_EQ(strcmp(parsed_config->health_check_service_name(),
                    "health_check_service_name"),
             0);
 }
@@ -974,14 +974,14 @@ TEST_F(MessageSizeParserTest, Valid) {
   auto svc_cfg = ServiceConfig::Create(test_json, &error);
   gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
   ASSERT_TRUE(error == GRPC_ERROR_NONE);
-  const auto* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector(
+  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   EXPECT_TRUE(vector_ptr != nullptr);
-  auto parsed_object =
-      static_cast<MessageSizeParsedObject*>(((*vector_ptr)[0]).get());
-  ASSERT_TRUE(parsed_object != nullptr);
-  EXPECT_EQ(parsed_object->limits().max_send_size, 1024);
-  EXPECT_EQ(parsed_object->limits().max_recv_size, 1024);
+  auto parsed_config =
+      static_cast<MessageSizeParsedConfig*>(((*vector_ptr)[0]).get());
+  ASSERT_TRUE(parsed_config != nullptr);
+  EXPECT_EQ(parsed_config->limits().max_send_size, 1024);
+  EXPECT_EQ(parsed_config->limits().max_recv_size, 1024);
 }
 
 TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) {
index 3ab5552..e01e6ad 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <grpc/support/log.h>
 
-#include "test/core/util/debugger_macros.h"
 
 static bool g_pre_init_called = false;
 
@@ -188,7 +187,6 @@ extern void write_buffering_at_end_pre_init(void);
 void grpc_end2end_tests_pre_init(void) {
   GPR_ASSERT(!g_pre_init_called);
   g_pre_init_called = true;
-  grpc_summon_debugger_macros();
   authority_not_supported_pre_init();
   bad_hostname_pre_init();
   bad_ping_pre_init();
index b680da4..76fb046 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <grpc/support/log.h>
 
-#include "test/core/util/debugger_macros.h"
 
 static bool g_pre_init_called = false;
 
@@ -190,7 +189,6 @@ extern void write_buffering_at_end_pre_init(void);
 void grpc_end2end_tests_pre_init(void) {
   GPR_ASSERT(!g_pre_init_called);
   g_pre_init_called = true;
-  grpc_summon_debugger_macros();
   authority_not_supported_pre_init();
   bad_hostname_pre_init();
   bad_ping_pre_init();
index f943128..4b7e467 100644 (file)
@@ -109,6 +109,24 @@ TEST(InlinedVectorTest, ConstIndexOperator) {
   const_func(v);
 }
 
+TEST(InlinedVectorTest, EqualOperator) {
+  constexpr int kNumElements = 10;
+  // Both v1 and v2 are empty.
+  InlinedVector<int, 5> v1;
+  InlinedVector<int, 5> v2;
+  EXPECT_TRUE(v1 == v2);
+  // Both v1 and v2 contains the same data.
+  FillVector(&v1, kNumElements);
+  FillVector(&v2, kNumElements);
+  EXPECT_TRUE(v1 == v2);
+  // The sizes of v1 and v2 are different.
+  v1.push_back(0);
+  EXPECT_FALSE(v1 == v2);
+  // The contents of v1 and v2 are different although their sizes are the same.
+  v2.push_back(1);
+  EXPECT_FALSE(v1 == v2);
+}
+
 // the following constants and typedefs are used for copy/move
 // construction/assignment
 const size_t kInlinedLength = 8;
index e70bf38..30d9eb0 100644 (file)
@@ -17,7 +17,9 @@
  */
 
 #include "src/core/lib/gprpp/map.h"
+
 #include <gtest/gtest.h>
+
 #include "include/grpc/support/string_util.h"
 #include "src/core/lib/gprpp/inlined_vector.h"
 #include "src/core/lib/gprpp/memory.h"
@@ -319,43 +321,49 @@ TEST_F(MapTest, MapRandomInsertions) {
 // Test Map iterator
 TEST_F(MapTest, Iteration) {
   Map<const char*, Payload, StringLess> test_map;
-  for (int i = 0; i < 5; i++) {
+  for (int i = 4; i >= 0; --i) {
     test_map.emplace(kKeys[i], Payload(i));
   }
-  int count = 0;
-  for (auto iter = test_map.begin(); iter != test_map.end(); iter++) {
-    EXPECT_EQ(iter->second.data(), count);
-    count++;
+  auto it = test_map.begin();
+  for (int i = 0; i < 5; ++i) {
+    ASSERT_NE(it, test_map.end());
+    EXPECT_STREQ(kKeys[i], it->first);
+    EXPECT_EQ(i, it->second.data());
+    ++it;
   }
-  EXPECT_EQ(count, 5);
+  EXPECT_EQ(it, test_map.end());
 }
 
 // Test Map iterator with unique ptr payload
 TEST_F(MapTest, IterationWithUniquePtrValue) {
   Map<const char*, UniquePtr<Payload>, StringLess> test_map;
-  for (int i = 0; i < 5; i++) {
+  for (int i = 4; i >= 0; --i) {
     test_map.emplace(kKeys[i], MakeUnique<Payload>(i));
   }
-  int count = 0;
-  for (auto iter = test_map.begin(); iter != test_map.end(); iter++) {
-    EXPECT_EQ(iter->second->data(), count);
-    count++;
+  auto it = test_map.begin();
+  for (int i = 0; i < 5; ++i) {
+    ASSERT_NE(it, test_map.end());
+    EXPECT_STREQ(kKeys[i], it->first);
+    EXPECT_EQ(i, it->second->data());
+    ++it;
   }
-  EXPECT_EQ(count, 5);
+  EXPECT_EQ(it, test_map.end());
 }
 
 // Test Map iterator with unique ptr to char key
 TEST_F(MapTest, IterationWithUniquePtrKey) {
   Map<UniquePtr<char>, Payload, StringLess> test_map;
-  for (int i = 0; i < 5; i++) {
+  for (int i = 4; i >= 0; --i) {
     test_map.emplace(CopyString(kKeys[i]), Payload(i));
   }
-  int count = 0;
-  for (auto iter = test_map.begin(); iter != test_map.end(); iter++) {
-    EXPECT_EQ(iter->second.data(), count);
-    count++;
+  auto it = test_map.begin();
+  for (int i = 0; i < 5; ++i) {
+    ASSERT_NE(it, test_map.end());
+    EXPECT_STREQ(kKeys[i], it->first.get());
+    EXPECT_EQ(i, it->second.data());
+    ++it;
   }
-  EXPECT_EQ(count, 5);
+  EXPECT_EQ(it, test_map.end());
 }
 
 // Test removing entries while iterating the map
@@ -367,11 +375,23 @@ TEST_F(MapTest, EraseUsingIterator) {
   int count = 0;
   for (auto iter = test_map.begin(); iter != test_map.end();) {
     EXPECT_EQ(iter->second.data(), count);
-    iter = test_map.erase(iter);
-    count++;
+    if (count % 2 == 1) {
+      iter = test_map.erase(iter);
+    } else {
+      ++iter;
+    }
+    ++count;
   }
   EXPECT_EQ(count, 5);
-  EXPECT_TRUE(test_map.empty());
+  auto it = test_map.begin();
+  for (int i = 0; i < 5; ++i) {
+    if (i % 2 == 0) {
+      EXPECT_STREQ(kKeys[i], it->first);
+      EXPECT_EQ(i, it->second.data());
+      ++it;
+    }
+  }
+  EXPECT_EQ(it, test_map.end());
 }
 
 // Random ops on a Map with Integer key of Payload value,
@@ -399,6 +419,24 @@ TEST_F(MapTest, RandomOpsWithIntKey) {
   EXPECT_TRUE(test_map.empty());
 }
 
+// Tests lower_bound().
+TEST_F(MapTest, LowerBound) {
+  Map<int, Payload> test_map;
+  for (int i = 0; i < 10; i += 2) {
+    test_map.emplace(i, Payload(i));
+  }
+  auto it = test_map.lower_bound(-1);
+  EXPECT_EQ(it, test_map.begin());
+  it = test_map.lower_bound(0);
+  EXPECT_EQ(it, test_map.begin());
+  it = test_map.lower_bound(2);
+  EXPECT_EQ(it->first, 2);
+  it = test_map.lower_bound(3);
+  EXPECT_EQ(it->first, 4);
+  it = test_map.lower_bound(9);
+  EXPECT_EQ(it, test_map.end());
+}
+
 }  // namespace testing
 }  // namespace grpc_core
 
index b53e331..7d4acfe 100644 (file)
@@ -19,6 +19,7 @@
 #include <grpc/grpc.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
 void test_slice_buffer_add() {
@@ -105,12 +106,54 @@ void test_slice_buffer_move_first() {
   GPR_ASSERT(dst.length == dst_len);
 }
 
+void test_slice_buffer_first() {
+  grpc_slice slices[3];
+  slices[0] = grpc_slice_from_copied_string("aaa");
+  slices[1] = grpc_slice_from_copied_string("bbbb");
+  slices[2] = grpc_slice_from_copied_string("ccccc");
+
+  grpc_slice_buffer buf;
+  grpc_slice_buffer_init(&buf);
+  for (int idx = 0; idx < 3; ++idx) {
+    grpc_slice_ref(slices[idx]);
+    grpc_slice_buffer_add_indexed(&buf, slices[idx]);
+  }
+
+  grpc_slice* first = grpc_slice_buffer_peek_first(&buf);
+  GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[0]));
+  GPR_ASSERT(buf.count == 3);
+  GPR_ASSERT(buf.length == 12);
+
+  grpc_slice_buffer_sub_first(&buf, 1, 2);
+  first = grpc_slice_buffer_peek_first(&buf);
+  GPR_ASSERT(GPR_SLICE_LENGTH(*first) == 1);
+  GPR_ASSERT(buf.count == 3);
+  GPR_ASSERT(buf.length == 10);
+
+  grpc_slice_buffer_remove_first(&buf);
+  first = grpc_slice_buffer_peek_first(&buf);
+  GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[1]));
+  GPR_ASSERT(buf.count == 2);
+  GPR_ASSERT(buf.length == 9);
+
+  grpc_slice_buffer_remove_first(&buf);
+  first = grpc_slice_buffer_peek_first(&buf);
+  GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[2]));
+  GPR_ASSERT(buf.count == 1);
+  GPR_ASSERT(buf.length == 5);
+
+  grpc_slice_buffer_remove_first(&buf);
+  GPR_ASSERT(buf.count == 0);
+  GPR_ASSERT(buf.length == 0);
+}
+
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   grpc_init();
 
   test_slice_buffer_add();
   test_slice_buffer_move_first();
+  test_slice_buffer_first();
 
   grpc_shutdown();
   return 0;
index 6ed0236..4f824cb 100644 (file)
@@ -27,6 +27,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "test/core/util/test_config.h"
@@ -285,6 +286,44 @@ static void test_static_slice_copy_interning(void) {
   grpc_shutdown();
 }
 
+static void test_moved_string_slice(void) {
+  LOG_TEST_NAME("test_moved_string_slice");
+
+  grpc_init();
+
+  // Small string should be inlined.
+  constexpr char kSmallStr[] = "hello12345";
+  char* small_ptr = strdup(kSmallStr);
+  grpc_slice small =
+      grpc_slice_from_moved_string(grpc_core::UniquePtr<char>(small_ptr));
+  GPR_ASSERT(GRPC_SLICE_LENGTH(small) == strlen(kSmallStr));
+  GPR_ASSERT(GRPC_SLICE_START_PTR(small) !=
+             reinterpret_cast<uint8_t*>(small_ptr));
+  grpc_slice_unref(small);
+
+  // Large string should be move the reference.
+  constexpr char kSLargeStr[] = "hello123456789123456789123456789";
+  char* large_ptr = strdup(kSLargeStr);
+  grpc_slice large =
+      grpc_slice_from_moved_string(grpc_core::UniquePtr<char>(large_ptr));
+  GPR_ASSERT(GRPC_SLICE_LENGTH(large) == strlen(kSLargeStr));
+  GPR_ASSERT(GRPC_SLICE_START_PTR(large) ==
+             reinterpret_cast<uint8_t*>(large_ptr));
+  grpc_slice_unref(large);
+
+  // Moved buffer must respect the provided length not the actual length of the
+  // string.
+  large_ptr = strdup(kSLargeStr);
+  small = grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char>(large_ptr),
+                                       strlen(kSmallStr));
+  GPR_ASSERT(GRPC_SLICE_LENGTH(small) == strlen(kSmallStr));
+  GPR_ASSERT(GRPC_SLICE_START_PTR(small) !=
+             reinterpret_cast<uint8_t*>(large_ptr));
+  grpc_slice_unref(small);
+
+  grpc_shutdown();
+}
+
 int main(int argc, char** argv) {
   unsigned length;
   grpc::testing::TestEnvironment env(argc, argv);
@@ -302,6 +341,7 @@ int main(int argc, char** argv) {
   test_slice_interning();
   test_static_slice_interning();
   test_static_slice_copy_interning();
+  test_moved_string_slice();
   grpc_shutdown();
   return 0;
 }
index 7c3630e..4a33b93 100644 (file)
@@ -23,6 +23,7 @@
 #include <grpc/support/time.h>
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
@@ -359,12 +360,19 @@ static void test_pluck_after_shutdown(void) {
 
 static void test_callback(void) {
   grpc_completion_queue* cc;
-  void* tags[128];
+  static void* tags[128];
   grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
   grpc_cq_polling_type polling_types[] = {
       GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
   grpc_completion_queue_attributes attr;
   unsigned i;
+  static gpr_mu mu, shutdown_mu;
+  static gpr_cv cv, shutdown_cv;
+  static int cb_counter;
+  gpr_mu_init(&mu);
+  gpr_mu_init(&shutdown_mu);
+  gpr_cv_init(&cv);
+  gpr_cv_init(&shutdown_cv);
 
   LOG_TEST("test_callback");
 
@@ -376,7 +384,11 @@ static void test_callback(void) {
     }
     ~ShutdownCallback() {}
     static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+      gpr_mu_lock(&shutdown_mu);
       *static_cast<ShutdownCallback*>(cb)->done_ = static_cast<bool>(ok);
+      // Signal when the shutdown callback is completed.
+      gpr_cv_signal(&shutdown_cv);
+      gpr_mu_unlock(&shutdown_mu);
     }
 
    private:
@@ -391,9 +403,9 @@ static void test_callback(void) {
   for (size_t pidx = 0; pidx < GPR_ARRAY_SIZE(polling_types); pidx++) {
     int sumtags = 0;
     int counter = 0;
+    cb_counter = 0;
     {
       // reset exec_ctx types
-      grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
       grpc_core::ExecCtx exec_ctx;
       attr.cq_polling_type = polling_types[pidx];
       cc = grpc_completion_queue_create(
@@ -409,7 +421,13 @@ static void test_callback(void) {
                         int ok) {
           GPR_ASSERT(static_cast<bool>(ok));
           auto* callback = static_cast<TagCallback*>(cb);
+          gpr_mu_lock(&mu);
+          cb_counter++;
           *callback->counter_ += callback->tag_;
+          if (cb_counter == GPR_ARRAY_SIZE(tags)) {
+            gpr_cv_signal(&cv);
+          }
+          gpr_mu_unlock(&mu);
           grpc_core::Delete(callback);
         };
 
@@ -429,12 +447,34 @@ static void test_callback(void) {
                        nullptr, &completions[i]);
       }
 
+      gpr_mu_lock(&mu);
+      while (cb_counter != GPR_ARRAY_SIZE(tags)) {
+        // Wait for all the callbacks to complete.
+        gpr_cv_wait(&cv, &mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+      }
+      gpr_mu_unlock(&mu);
+
       shutdown_and_destroy(cc);
+
+      gpr_mu_lock(&shutdown_mu);
+      while (!got_shutdown) {
+        // Wait for the shutdown callback to complete.
+        gpr_cv_wait(&shutdown_cv, &shutdown_mu,
+                    gpr_inf_future(GPR_CLOCK_REALTIME));
+      }
+      gpr_mu_unlock(&shutdown_mu);
     }
+
+    // Run the assertions to check if the test ran successfully.
     GPR_ASSERT(sumtags == counter);
     GPR_ASSERT(got_shutdown);
     got_shutdown = false;
   }
+
+  gpr_cv_destroy(&cv);
+  gpr_cv_destroy(&shutdown_cv);
+  gpr_mu_destroy(&mu);
+  gpr_mu_destroy(&shutdown_mu);
 }
 
 struct thread_state {
index fa02e76..3aaa1e7 100644 (file)
@@ -161,6 +161,7 @@ int main(int argc, char **argv) {
   printf("%lx", (unsigned long) grpc_google_default_credentials_create);
   printf("%lx", (unsigned long) grpc_set_ssl_roots_override_callback);
   printf("%lx", (unsigned long) grpc_ssl_credentials_create);
+  printf("%lx", (unsigned long) grpc_ssl_credentials_create_ex);
   printf("%lx", (unsigned long) grpc_call_credentials_release);
   printf("%lx", (unsigned long) grpc_composite_channel_credentials_create);
   printf("%lx", (unsigned long) grpc_composite_call_credentials_create);
index fed6ad9..fde68f3 100644 (file)
@@ -21,7 +21,6 @@
  * Not intended to be robust for main-line code, often cuts across abstraction
  * boundaries.
  */
-
 #include <stdio.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
@@ -29,8 +28,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/surface/call.h"
 
-void grpc_summon_debugger_macros() {}
-
 grpc_stream* grpc_transport_stream_from_call(grpc_call* call) {
   grpc_call_stack* cs = grpc_call_get_call_stack(call);
   for (;;) {
index c6b3720..71228c6 100644 (file)
@@ -19,6 +19,9 @@
 #ifndef GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
 #define GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
 
-void grpc_summon_debugger_macros();
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/surface/call.h"
+
+grpc_chttp2_stream* grpc_chttp2_stream_from_call(grpc_call* call);
 
 #endif /* GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H */
index b871f04..2c1f988 100644 (file)
@@ -72,12 +72,6 @@ class ForwardingLoadBalancingPolicy : public LoadBalancingPolicy {
 
   void ResetBackoffLocked() override { delegate_->ResetBackoffLocked(); }
 
-  void FillChildRefsForChannelz(
-      channelz::ChildRefsList* child_subchannels,
-      channelz::ChildRefsList* child_channels) override {
-    delegate_->FillChildRefsForChannelz(child_subchannels, child_channels);
-  }
-
  private:
   void ShutdownLocked() override { delegate_.reset(); }
 
@@ -120,10 +114,12 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
           cb_(cb),
           user_data_(user_data) {}
 
-    PickResult Pick(PickArgs* pick, grpc_error** error) override {
-      PickResult result = delegate_picker_->Pick(pick, error);
-      if (result == PICK_COMPLETE && pick->connected_subchannel != nullptr) {
-        New<TrailingMetadataHandler>(pick, cb_, user_data_);  // deletes itself
+    PickResult Pick(PickArgs args) override {
+      PickResult result = delegate_picker_->Pick(args);
+      if (result.type == PickResult::PICK_COMPLETE &&
+          result.connected_subchannel != nullptr) {
+        new (args.call_state->Alloc(sizeof(TrailingMetadataHandler)))
+            TrailingMetadataHandler(&result, cb_, user_data_);
       }
       return result;
     }
@@ -141,7 +137,8 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
         InterceptRecvTrailingMetadataCallback cb, void* user_data)
         : parent_(std::move(parent)), cb_(cb), user_data_(user_data) {}
 
-    Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
+    RefCountedPtr<SubchannelInterface> CreateSubchannel(
+        const grpc_channel_args& args) override {
       return parent_->channel_control_helper()->CreateSubchannel(args);
     }
 
@@ -161,6 +158,10 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
       parent_->channel_control_helper()->RequestReresolution();
     }
 
+    void AddTraceEvent(TraceSeverity severity, const char* message) override {
+      parent_->channel_control_helper()->AddTraceEvent(severity, message);
+    }
+
    private:
     RefCountedPtr<InterceptRecvTrailingMetadataLoadBalancingPolicy> parent_;
     InterceptRecvTrailingMetadataCallback cb_;
@@ -169,35 +170,27 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
 
   class TrailingMetadataHandler {
    public:
-    TrailingMetadataHandler(PickArgs* pick,
+    TrailingMetadataHandler(PickResult* result,
                             InterceptRecvTrailingMetadataCallback cb,
                             void* user_data)
         : cb_(cb), user_data_(user_data) {
-      GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
-                        RecordRecvTrailingMetadata, this,
-                        grpc_schedule_on_exec_ctx);
-      pick->recv_trailing_metadata_ready = &recv_trailing_metadata_ready_;
-      pick->original_recv_trailing_metadata_ready =
-          &original_recv_trailing_metadata_ready_;
-      pick->recv_trailing_metadata = &recv_trailing_metadata_;
+      result->recv_trailing_metadata_ready = &RecordRecvTrailingMetadata;
+      result->recv_trailing_metadata_ready_user_data = this;
     }
 
    private:
-    static void RecordRecvTrailingMetadata(void* arg, grpc_error* err) {
+    static void RecordRecvTrailingMetadata(
+        void* arg, grpc_metadata_batch* recv_trailing_metadata,
+        CallState* call_state) {
       TrailingMetadataHandler* self =
           static_cast<TrailingMetadataHandler*>(arg);
-      GPR_ASSERT(self->recv_trailing_metadata_ != nullptr);
+      GPR_ASSERT(recv_trailing_metadata != nullptr);
       self->cb_(self->user_data_);
-      GRPC_CLOSURE_SCHED(self->original_recv_trailing_metadata_ready_,
-                         GRPC_ERROR_REF(err));
-      Delete(self);
+      self->~TrailingMetadataHandler();
     }
 
     InterceptRecvTrailingMetadataCallback cb_;
     void* user_data_;
-    grpc_closure recv_trailing_metadata_ready_;
-    grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
-    grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
   };
 };
 
index 80d0634..170584d 100644 (file)
@@ -102,6 +102,7 @@ void test_tcp_server_destroy(test_tcp_server* server) {
                     grpc_schedule_on_exec_ctx);
   shutdown_deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                                    gpr_time_from_seconds(5, GPR_TIMESPAN));
+  grpc_core::ExecCtx::Get()->Flush();
   while (!server->shutdown &&
          gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), shutdown_deadline) < 0) {
     test_tcp_server_poll(server, 1000);
index e571a95..64ab123 100644 (file)
@@ -41,9 +41,9 @@
 #include <grpcpp/impl/codegen/sync_stream.h>
 
 namespace grpc_impl {
-class Channel;
 class CompletionQueue;
 class ServerCompletionQueue;
+class ServerContext;
 }  // namespace grpc_impl
 
 namespace grpc {
@@ -51,10 +51,6 @@ namespace experimental {
 template <typename RequestT, typename ResponseT>
 class MessageAllocator;
 }  // namespace experimental
-}  // namespace grpc_impl
-
-namespace grpc {
-class ServerContext;
 }  // namespace grpc
 
 namespace grpc {
index 519a33f..d229cc3 100644 (file)
@@ -717,3 +717,21 @@ grpc_cc_test(
     ],
 )
 
+grpc_cc_test(
+    name = "port_sharing_end2end_test",
+    srcs = ["port_sharing_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        ":test_service_impl",
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/testing:echo_messages_proto",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
+
index 59cf98f..1c93208 100644 (file)
@@ -42,6 +42,7 @@
 #include "src/core/lib/gpr/env.h"
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/debugger_macros.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/end2end/test_service_impl.h"
@@ -144,6 +145,18 @@ class CFStreamTest : public ::testing::TestWithParam<TestScenario> {
     return CreateCustomChannel(server_address.str(), channel_creds, args);
   }
 
+  int GetStreamID(ClientContext& context) {
+    int stream_id = 0;
+    grpc_call* call = context.c_call();
+    if (call) {
+      grpc_chttp2_stream* stream = grpc_chttp2_stream_from_call(call);
+      if (stream) {
+        stream_id = stream->id;
+      }
+    }
+    return stream_id;
+  }
+
   void SendRpc(
       const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
       bool expect_success = false) {
@@ -153,10 +166,13 @@ class CFStreamTest : public ::testing::TestWithParam<TestScenario> {
     request.set_message(msg);
     ClientContext context;
     Status status = stub->Echo(&context, request, response.get());
+    int stream_id = GetStreamID(context);
     if (status.ok()) {
+      gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id);
       EXPECT_EQ(msg, response->message());
     } else {
-      gpr_log(GPR_DEBUG, "RPC failed: %s", status.error_message().c_str());
+      gpr_log(GPR_DEBUG, "RPC with stream_id %d failed: %s", stream_id,
+              status.error_message().c_str());
     }
     if (expect_success) {
       EXPECT_TRUE(status.ok());
@@ -341,7 +357,9 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) {
 
   // Channel should be in READY state after we send some RPCs
   for (int i = 0; i < 10; ++i) {
-    SendAsyncRpc(stub);
+    RequestParams param;
+    param.set_skip_cancelled_check(true);
+    SendAsyncRpc(stub, param);
     ++rpcs_sent;
   }
   EXPECT_TRUE(WaitForChannelReady(channel.get()));
@@ -359,14 +377,17 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) {
       ++total_completions;
       GPR_ASSERT(ok);
       AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
+      int stream_id = GetStreamID(call->context);
       if (!call->status.ok()) {
-        gpr_log(GPR_DEBUG, "RPC failed with error: %s",
-                call->status.error_message().c_str());
+        gpr_log(GPR_DEBUG, "RPC with stream_id %d failed with error: %s",
+                stream_id, call->status.error_message().c_str());
         // Bring network up when RPCs start failing
         if (network_down) {
           NetworkUp();
           network_down = false;
         }
+      } else {
+        gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id);
       }
       delete call;
     }
@@ -374,7 +395,9 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) {
   });
 
   for (int i = 0; i < 100; ++i) {
-    SendAsyncRpc(stub);
+    RequestParams param;
+    param.set_skip_cancelled_check(true);
+    SendAsyncRpc(stub, param);
     std::this_thread::sleep_for(std::chrono::milliseconds(10));
     ++rpcs_sent;
   }
@@ -393,21 +416,19 @@ TEST_P(CFStreamTest, ConcurrentRpc) {
   std::thread thd = std::thread([this, &rpcs_sent]() {
     void* got_tag;
     bool ok = false;
-    bool network_down = true;
     int total_completions = 0;
 
     while (CQNext(&got_tag, &ok)) {
       ++total_completions;
       GPR_ASSERT(ok);
       AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
+      int stream_id = GetStreamID(call->context);
       if (!call->status.ok()) {
-        gpr_log(GPR_DEBUG, "RPC failed: %s",
-                call->status.error_message().c_str());
+        gpr_log(GPR_DEBUG, "RPC with stream_id %d failed with error: %s",
+                stream_id, call->status.error_message().c_str());
         // Bring network up when RPCs start failing
-        if (network_down) {
-          NetworkUp();
-          network_down = false;
-        }
+      } else {
+        gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id);
       }
       delete call;
     }
index 26ef59f..69c56c5 100644 (file)
@@ -163,13 +163,12 @@ class ChannelzServerTest : public ::testing::Test {
   }
 
   std::unique_ptr<grpc::testing::EchoTestService::Stub> NewEchoStub() {
-    static int salt = 0;
     string target = "dns:localhost:" + to_string(proxy_port_);
     ChannelArguments args;
     // disable channelz. We only want to focus on proxy to backend outbound.
     args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 0);
     // This ensures that gRPC will not do connection sharing.
-    args.SetInt("salt", salt++);
+    args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, true);
     std::shared_ptr<Channel> channel =
         ::grpc::CreateCustomChannel(target, InsecureChannelCredentials(), args);
     return grpc::testing::EchoTestService::NewStub(channel);
index ede24f3..8cf6def 100644 (file)
@@ -104,10 +104,6 @@ class ClientCallbackEnd2endTest
     // TODO(vjpai): Support testing of AuthMetadataProcessor
 
     if (GetParam().protocol == Protocol::TCP) {
-      if (!grpc_iomgr_run_in_background()) {
-        do_not_test_ = true;
-        return;
-      }
       picked_port_ = grpc_pick_unused_port_or_die();
       server_address_ << "localhost:" << picked_port_;
       builder.AddListeningPort(server_address_.str(), server_creds);
@@ -133,6 +129,10 @@ class ClientCallbackEnd2endTest
 
     server_ = builder.BuildAndStart();
     is_server_started_ = true;
+    if (GetParam().protocol == Protocol::TCP &&
+        !grpc_iomgr_run_in_background()) {
+      do_not_test_ = true;
+    }
   }
 
   void ResetStub() {
@@ -374,6 +374,34 @@ TEST_P(ClientCallbackEnd2endTest, SimpleRpc) {
   SendRpcs(1, false);
 }
 
+TEST_P(ClientCallbackEnd2endTest, SimpleRpcUnderLock) {
+  MAYBE_SKIP_TEST;
+  ResetStub();
+  std::mutex mu;
+  std::condition_variable cv;
+  bool done = false;
+  EchoRequest request;
+  request.set_message("Hello locked world.");
+  EchoResponse response;
+  ClientContext cli_ctx;
+  {
+    std::lock_guard<std::mutex> l(mu);
+    stub_->experimental_async()->Echo(
+        &cli_ctx, &request, &response,
+        [&mu, &cv, &done, &request, &response](Status s) {
+          std::lock_guard<std::mutex> l(mu);
+          EXPECT_TRUE(s.ok());
+          EXPECT_EQ(request.message(), response.message());
+          done = true;
+          cv.notify_one();
+        });
+  }
+  std::unique_lock<std::mutex> l(mu);
+  while (!done) {
+    cv.wait(l);
+  }
+}
+
 TEST_P(ClientCallbackEnd2endTest, SequentialRpcs) {
   MAYBE_SKIP_TEST;
   ResetStub();
index f1aed09..583513e 100644 (file)
@@ -499,9 +499,20 @@ class BidiStreamingRpcHijackingInterceptorFactory
   }
 };
 
+// The logging interceptor is for testing purposes only. It is used to verify
+// that all the appropriate hook points are invoked for an RPC. The counts are
+// reset each time a new object of LoggingInterceptor is created, so only a
+// single RPC should be made on the channel before calling the Verify methods.
 class LoggingInterceptor : public experimental::Interceptor {
  public:
-  LoggingInterceptor(experimental::ClientRpcInfo* info) { info_ = info; }
+  LoggingInterceptor(experimental::ClientRpcInfo* info) {
+    pre_send_initial_metadata_ = false;
+    pre_send_message_count_ = 0;
+    pre_send_close_ = false;
+    post_recv_initial_metadata_ = false;
+    post_recv_message_count_ = 0;
+    post_recv_status_ = false;
+  }
 
   virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
     if (methods->QueryInterceptionHookPoint(
@@ -512,6 +523,8 @@ class LoggingInterceptor : public experimental::Interceptor {
       auto iterator = map->begin();
       EXPECT_EQ("testkey", iterator->first);
       EXPECT_EQ("testvalue", iterator->second);
+      ASSERT_FALSE(pre_send_initial_metadata_);
+      pre_send_initial_metadata_ = true;
     }
     if (methods->QueryInterceptionHookPoint(
             experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
@@ -526,22 +539,28 @@ class LoggingInterceptor : public experimental::Interceptor {
           SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
               .ok());
       EXPECT_TRUE(req.message().find("Hello") == 0u);
+      pre_send_message_count_++;
     }
     if (methods->QueryInterceptionHookPoint(
             experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
       // Got nothing to do here for now
+      pre_send_close_ = true;
     }
     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));
+      post_recv_initial_metadata_ = true;
     }
     if (methods->QueryInterceptionHookPoint(
             experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
       EchoResponse* resp =
           static_cast<EchoResponse*>(methods->GetRecvMessage());
-      EXPECT_TRUE(resp->message().find("Hello") == 0u);
+      if (resp != nullptr) {
+        EXPECT_TRUE(resp->message().find("Hello") == 0u);
+        post_recv_message_count_++;
+      }
     }
     if (methods->QueryInterceptionHookPoint(
             experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
@@ -556,14 +575,58 @@ class LoggingInterceptor : public experimental::Interceptor {
       EXPECT_EQ(found, true);
       auto* status = methods->GetRecvStatus();
       EXPECT_EQ(status->ok(), true);
+      post_recv_status_ = true;
     }
     methods->Proceed();
   }
 
+  static void VerifyCallCommon() {
+    EXPECT_TRUE(pre_send_initial_metadata_);
+    EXPECT_TRUE(pre_send_close_);
+    EXPECT_TRUE(post_recv_initial_metadata_);
+    EXPECT_TRUE(post_recv_status_);
+  }
+
+  static void VerifyUnaryCall() {
+    VerifyCallCommon();
+    EXPECT_EQ(pre_send_message_count_, 1);
+    EXPECT_EQ(post_recv_message_count_, 1);
+  }
+
+  static void VerifyClientStreamingCall() {
+    VerifyCallCommon();
+    EXPECT_EQ(pre_send_message_count_, kNumStreamingMessages);
+    EXPECT_EQ(post_recv_message_count_, 1);
+  }
+
+  static void VerifyServerStreamingCall() {
+    VerifyCallCommon();
+    EXPECT_EQ(pre_send_message_count_, 1);
+    EXPECT_EQ(post_recv_message_count_, kNumStreamingMessages);
+  }
+
+  static void VerifyBidiStreamingCall() {
+    VerifyCallCommon();
+    EXPECT_EQ(pre_send_message_count_, kNumStreamingMessages);
+    EXPECT_EQ(post_recv_message_count_, kNumStreamingMessages);
+  }
+
  private:
-  experimental::ClientRpcInfo* info_;
+  static bool pre_send_initial_metadata_;
+  static int pre_send_message_count_;
+  static bool pre_send_close_;
+  static bool post_recv_initial_metadata_;
+  static int post_recv_message_count_;
+  static bool post_recv_status_;
 };
 
+bool LoggingInterceptor::pre_send_initial_metadata_;
+int LoggingInterceptor::pre_send_message_count_;
+bool LoggingInterceptor::pre_send_close_;
+bool LoggingInterceptor::post_recv_initial_metadata_;
+int LoggingInterceptor::post_recv_message_count_;
+bool LoggingInterceptor::post_recv_status_;
+
 class LoggingInterceptorFactory
     : public experimental::ClientInterceptorFactoryInterface {
  public:
@@ -607,6 +670,7 @@ TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLoggingTest) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
   MakeCall(channel);
+  LoggingInterceptor::VerifyUnaryCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -643,7 +707,6 @@ TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorHijackingTest) {
   }
   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);
@@ -659,8 +722,8 @@ TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLogThenHijackTest) {
       new HijackingInterceptorFactory()));
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
-
   MakeCall(channel);
+  LoggingInterceptor::VerifyUnaryCall();
 }
 
 TEST_F(ClientInterceptorsEnd2endTest,
@@ -708,6 +771,7 @@ TEST_F(ClientInterceptorsEnd2endTest,
   auto channel = server_->experimental().InProcessChannelWithInterceptors(
       args, std::move(creators));
   MakeCallbackCall(channel);
+  LoggingInterceptor::VerifyUnaryCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -730,6 +794,7 @@ TEST_F(ClientInterceptorsEnd2endTest,
   auto channel = server_->experimental().InProcessChannelWithInterceptors(
       args, std::move(creators));
   MakeCallbackCall(channel);
+  LoggingInterceptor::VerifyUnaryCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -768,6 +833,7 @@ TEST_F(ClientInterceptorsStreamingEnd2endTest, ClientStreamingTest) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
   MakeClientStreamingCall(channel);
+  LoggingInterceptor::VerifyClientStreamingCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -787,6 +853,7 @@ TEST_F(ClientInterceptorsStreamingEnd2endTest, ServerStreamingTest) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
   MakeServerStreamingCall(channel);
+  LoggingInterceptor::VerifyServerStreamingCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -862,6 +929,7 @@ TEST_F(ClientInterceptorsStreamingEnd2endTest, BidiStreamingTest) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
   MakeBidiStreamingCall(channel);
+  LoggingInterceptor::VerifyBidiStreamingCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
 }
@@ -928,6 +996,7 @@ TEST_F(ClientGlobalInterceptorEnd2endTest, LoggingGlobalInterceptor) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
   MakeCall(channel);
+  LoggingInterceptor::VerifyUnaryCall();
   // Make sure all 20 dummy interceptors were run
   EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
   experimental::TestOnlyResetGlobalClientInterceptorFactory();
index 766c38a..f6d4a48 100644 (file)
@@ -139,11 +139,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
       : 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_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
-  }
+            grpc_fake_transport_security_credentials_create())) {}
 
   void SetUp() override {
     grpc_init();
@@ -1019,8 +1015,8 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
   auto channel = BuildChannel("round_robin");
   auto stub = BuildStub(channel);
   std::vector<int> ports;
-
   // Start with a single server.
+  gpr_log(GPR_INFO, "*** FIRST BACKEND ***");
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
   WaitForServer(stub, 0, DEBUG_LOCATION);
@@ -1030,36 +1026,33 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   EXPECT_EQ(0, servers_[2]->service_.request_count());
   servers_[0]->service_.ResetCounters();
-
   // And now for the second server.
+  gpr_log(GPR_INFO, "*** SECOND BACKEND ***");
   ports.clear();
   ports.emplace_back(servers_[1]->port_);
   SetNextResolution(ports);
-
   // Wait until update has been processed, as signaled by the second backend
   // receiving a request.
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   WaitForServer(stub, 1, DEBUG_LOCATION);
-
   for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(0, servers_[0]->service_.request_count());
   EXPECT_EQ(10, servers_[1]->service_.request_count());
   EXPECT_EQ(0, servers_[2]->service_.request_count());
   servers_[1]->service_.ResetCounters();
-
   // ... and for the last server.
+  gpr_log(GPR_INFO, "*** THIRD BACKEND ***");
   ports.clear();
   ports.emplace_back(servers_[2]->port_);
   SetNextResolution(ports);
   WaitForServer(stub, 2, DEBUG_LOCATION);
-
   for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(0, servers_[0]->service_.request_count());
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   EXPECT_EQ(10, servers_[2]->service_.request_count());
   servers_[2]->service_.ResetCounters();
-
   // Back to all servers.
+  gpr_log(GPR_INFO, "*** ALL BACKENDS ***");
   ports.clear();
   ports.emplace_back(servers_[0]->port_);
   ports.emplace_back(servers_[1]->port_);
@@ -1068,14 +1061,13 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
   WaitForServer(stub, 0, DEBUG_LOCATION);
   WaitForServer(stub, 1, DEBUG_LOCATION);
   WaitForServer(stub, 2, DEBUG_LOCATION);
-
   // Send three RPCs, one per server.
   for (size_t i = 0; i < 3; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(1, servers_[0]->service_.request_count());
   EXPECT_EQ(1, servers_[1]->service_.request_count());
   EXPECT_EQ(1, servers_[2]->service_.request_count());
-
   // An empty update will result in the channel going into TRANSIENT_FAILURE.
+  gpr_log(GPR_INFO, "*** NO BACKENDS ***");
   ports.clear();
   SetNextResolution(ports);
   grpc_connectivity_state channel_state;
@@ -1084,15 +1076,14 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
   } while (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.
+  gpr_log(GPR_INFO, "*** BACK TO SECOND BACKEND ***");
   ports.clear();
   ports.emplace_back(servers_[1]->port_);
   SetNextResolution(ports);
   WaitForServer(stub, 1, DEBUG_LOCATION);
   channel_state = channel->GetState(false /* try to connect */);
   ASSERT_EQ(channel_state, GRPC_CHANNEL_READY);
-
   // Check LB policy name for the channel.
   EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
 }
@@ -1211,8 +1202,9 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
   auto channel = BuildChannel("round_robin");
   auto stub = BuildStub(channel);
   SetNextResolution(ports);
-  for (size_t i = 0; i < kNumServers; ++i)
+  for (size_t i = 0; i < kNumServers; ++i) {
     WaitForServer(stub, i, DEBUG_LOCATION);
+  }
   for (size_t i = 0; i < servers_.size(); ++i) {
     CheckRpcSendOk(stub, DEBUG_LOCATION);
     EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i;
@@ -1236,7 +1228,6 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
   // No requests have gone to the deceased server.
   EXPECT_EQ(pre_death, post_death);
   // Bring the first server back up.
-  servers_[0].reset(new ServerData(ports[0]));
   StartServer(0);
   // Requests should start arriving at the first server either right away (if
   // the server managed to start before the RR policy retried the subchannel) or
@@ -1360,6 +1351,52 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingInhibitPerChannel) {
   // Second channel should be READY.
   EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1));
   CheckRpcSendOk(stub2, DEBUG_LOCATION);
+  // Enable health checks on the backend and wait for channel 1 to succeed.
+  servers_[0]->SetServingStatus("health_check_service_name", true);
+  CheckRpcSendOk(stub1, DEBUG_LOCATION, true /* wait_for_ready */);
+  // Check that we created only one subchannel to the backend.
+  EXPECT_EQ(1UL, servers_[0]->service_.clients().size());
+  // Clean up.
+  EnableDefaultHealthCheckService(false);
+}
+
+TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingServiceNamePerChannel) {
+  EnableDefaultHealthCheckService(true);
+  // Start server.
+  const int kNumServers = 1;
+  StartServers(kNumServers);
+  // Create a channel with health-checking enabled.
+  ChannelArguments args;
+  args.SetServiceConfigJSON(
+      "{\"healthCheckConfig\": "
+      "{\"serviceName\": \"health_check_service_name\"}}");
+  auto channel1 = BuildChannel("round_robin", args);
+  auto stub1 = BuildStub(channel1);
+  std::vector<int> ports = GetServersPorts();
+  SetNextResolution(ports);
+  // Create a channel with health-checking enabled with a different
+  // service name.
+  ChannelArguments args2;
+  args2.SetServiceConfigJSON(
+      "{\"healthCheckConfig\": "
+      "{\"serviceName\": \"health_check_service_name2\"}}");
+  auto channel2 = BuildChannel("round_robin", args2);
+  auto stub2 = BuildStub(channel2);
+  SetNextResolution(ports);
+  // Allow health checks from channel 2 to succeed.
+  servers_[0]->SetServingStatus("health_check_service_name2", true);
+  // First channel should not become READY, because health checks should be
+  // failing.
+  EXPECT_FALSE(WaitForChannelReady(channel1.get(), 1));
+  CheckRpcSendFailure(stub1);
+  // Second channel should be READY.
+  EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1));
+  CheckRpcSendOk(stub2, DEBUG_LOCATION);
+  // Enable health checks for channel 1 and wait for it to succeed.
+  servers_[0]->SetServingStatus("health_check_service_name", true);
+  CheckRpcSendOk(stub1, DEBUG_LOCATION, true /* wait_for_ready */);
+  // Check that we created only one subchannel to the backend.
+  EXPECT_EQ(1UL, servers_[0]->service_.clients().size());
   // Clean up.
   EnableDefaultHealthCheckService(false);
 }
@@ -1444,6 +1481,9 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesEnabled) {
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  // Make the backup poller poll very frequently in order to pick up
+  // updates from all the subchannels's FDs.
+  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
   ::testing::InitGoogleTest(&argc, argv);
   grpc::testing::TestEnvironment env(argc, argv);
   const auto result = RUN_ALL_TESTS();
index 8fae2da..a8592fd 100644 (file)
@@ -26,6 +26,7 @@
 #include <grpcpp/channel.h>
 #include <grpcpp/client_context.h>
 #include <grpcpp/create_channel.h>
+#include <grpcpp/impl/codegen/status_code_enum.h>
 #include <grpcpp/resource_quota.h>
 #include <grpcpp/security/auth_metadata_processor.h>
 #include <grpcpp/security/credentials.h>
@@ -90,11 +91,13 @@ class TestMetadataCredentialsPlugin : public MetadataCredentialsPlugin {
 
   TestMetadataCredentialsPlugin(const grpc::string_ref& metadata_key,
                                 const grpc::string_ref& metadata_value,
-                                bool is_blocking, bool is_successful)
+                                bool is_blocking, bool is_successful,
+                                int delay_ms)
       : metadata_key_(metadata_key.data(), metadata_key.length()),
         metadata_value_(metadata_value.data(), metadata_value.length()),
         is_blocking_(is_blocking),
-        is_successful_(is_successful) {}
+        is_successful_(is_successful),
+        delay_ms_(delay_ms) {}
 
   bool IsBlocking() const override { return is_blocking_; }
 
@@ -102,6 +105,11 @@ class TestMetadataCredentialsPlugin : public MetadataCredentialsPlugin {
       grpc::string_ref service_url, grpc::string_ref method_name,
       const grpc::AuthContext& channel_auth_context,
       std::multimap<grpc::string, grpc::string>* metadata) override {
+    if (delay_ms_ != 0) {
+      gpr_sleep_until(
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                       gpr_time_from_millis(delay_ms_, GPR_TIMESPAN)));
+    }
     EXPECT_GT(service_url.length(), 0UL);
     EXPECT_GT(method_name.length(), 0UL);
     EXPECT_TRUE(channel_auth_context.IsPeerAuthenticated());
@@ -119,6 +127,7 @@ class TestMetadataCredentialsPlugin : public MetadataCredentialsPlugin {
   grpc::string metadata_value_;
   bool is_blocking_;
   bool is_successful_;
+  int delay_ms_;
 };
 
 const char TestMetadataCredentialsPlugin::kBadMetadataKey[] =
@@ -137,7 +146,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
         std::unique_ptr<MetadataCredentialsPlugin>(
             new TestMetadataCredentialsPlugin(
                 TestMetadataCredentialsPlugin::kGoodMetadataKey, kGoodGuy,
-                is_blocking_, true)));
+                is_blocking_, true, 0)));
   }
 
   std::shared_ptr<CallCredentials> GetIncompatibleClientCreds() {
@@ -145,7 +154,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
         std::unique_ptr<MetadataCredentialsPlugin>(
             new TestMetadataCredentialsPlugin(
                 TestMetadataCredentialsPlugin::kGoodMetadataKey, "Mr Hyde",
-                is_blocking_, true)));
+                is_blocking_, true, 0)));
   }
 
   // Interface implementation
@@ -1835,7 +1844,8 @@ TEST_P(SecureEnd2endTest, AuthMetadataPluginKeyFailure) {
       std::unique_ptr<MetadataCredentialsPlugin>(
           new TestMetadataCredentialsPlugin(
               TestMetadataCredentialsPlugin::kBadMetadataKey,
-              "Does not matter, will fail the key is invalid.", false, true))));
+              "Does not matter, will fail the key is invalid.", false, true,
+              0))));
   request.set_message("Hello");
 
   Status s = stub_->Echo(&context, request, &response);
@@ -1853,7 +1863,7 @@ TEST_P(SecureEnd2endTest, AuthMetadataPluginValueFailure) {
       std::unique_ptr<MetadataCredentialsPlugin>(
           new TestMetadataCredentialsPlugin(
               TestMetadataCredentialsPlugin::kGoodMetadataKey,
-              "With illegal \n value.", false, true))));
+              "With illegal \n value.", false, true, 0))));
   request.set_message("Hello");
 
   Status s = stub_->Echo(&context, request, &response);
@@ -1861,6 +1871,57 @@ TEST_P(SecureEnd2endTest, AuthMetadataPluginValueFailure) {
   EXPECT_EQ(s.error_code(), StatusCode::UNAVAILABLE);
 }
 
+TEST_P(SecureEnd2endTest, AuthMetadataPluginWithDeadline) {
+  MAYBE_SKIP_TEST;
+  ResetStub();
+  EchoRequest request;
+  request.mutable_param()->set_skip_cancelled_check(true);
+  EchoResponse response;
+  ClientContext context;
+  const int delay = 100;
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::milliseconds(delay);
+  context.set_deadline(deadline);
+  context.set_credentials(grpc::MetadataCredentialsFromPlugin(
+      std::unique_ptr<MetadataCredentialsPlugin>(
+          new TestMetadataCredentialsPlugin("meta_key", "Does not matter", true,
+                                            true, delay))));
+  request.set_message("Hello");
+
+  Status s = stub_->Echo(&context, request, &response);
+  if (!s.ok()) {
+    EXPECT_TRUE(s.error_code() == StatusCode::DEADLINE_EXCEEDED ||
+                s.error_code() == StatusCode::UNAVAILABLE);
+  }
+}
+
+TEST_P(SecureEnd2endTest, AuthMetadataPluginWithCancel) {
+  MAYBE_SKIP_TEST;
+  ResetStub();
+  EchoRequest request;
+  request.mutable_param()->set_skip_cancelled_check(true);
+  EchoResponse response;
+  ClientContext context;
+  const int delay = 100;
+  context.set_credentials(grpc::MetadataCredentialsFromPlugin(
+      std::unique_ptr<MetadataCredentialsPlugin>(
+          new TestMetadataCredentialsPlugin("meta_key", "Does not matter", true,
+                                            true, delay))));
+  request.set_message("Hello");
+
+  std::thread cancel_thread([&] {
+    gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                 gpr_time_from_millis(delay, GPR_TIMESPAN)));
+    context.TryCancel();
+  });
+  Status s = stub_->Echo(&context, request, &response);
+  if (!s.ok()) {
+    EXPECT_TRUE(s.error_code() == StatusCode::CANCELLED ||
+                s.error_code() == StatusCode::UNAVAILABLE);
+  }
+  cancel_thread.join();
+}
+
 TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginFailure) {
   MAYBE_SKIP_TEST;
   ResetStub();
@@ -1871,8 +1932,8 @@ TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginFailure) {
       std::unique_ptr<MetadataCredentialsPlugin>(
           new TestMetadataCredentialsPlugin(
               TestMetadataCredentialsPlugin::kGoodMetadataKey,
-              "Does not matter, will fail anyway (see 3rd param)", false,
-              false))));
+              "Does not matter, will fail anyway (see 3rd param)", false, false,
+              0))));
   request.set_message("Hello");
 
   Status s = stub_->Echo(&context, request, &response);
@@ -1935,8 +1996,8 @@ TEST_P(SecureEnd2endTest, BlockingAuthMetadataPluginFailure) {
       std::unique_ptr<MetadataCredentialsPlugin>(
           new TestMetadataCredentialsPlugin(
               TestMetadataCredentialsPlugin::kGoodMetadataKey,
-              "Does not matter, will fail anyway (see 3rd param)", true,
-              false))));
+              "Does not matter, will fail anyway (see 3rd param)", true, false,
+              0))));
   request.set_message("Hello");
 
   Status s = stub_->Echo(&context, request, &response);
@@ -1962,11 +2023,11 @@ TEST_P(SecureEnd2endTest, CompositeCallCreds) {
       grpc::MetadataCredentialsFromPlugin(
           std::unique_ptr<MetadataCredentialsPlugin>(
               new TestMetadataCredentialsPlugin(kMetadataKey1, kMetadataVal1,
-                                                true, true))),
+                                                true, true, 0))),
       grpc::MetadataCredentialsFromPlugin(
           std::unique_ptr<MetadataCredentialsPlugin>(
               new TestMetadataCredentialsPlugin(kMetadataKey2, kMetadataVal2,
-                                                true, true)))));
+                                                true, true, 0)))));
   request.set_message("Hello");
   request.mutable_param()->set_echo_metadata(true);
 
@@ -2114,6 +2175,10 @@ INSTANTIATE_TEST_CASE_P(
 int main(int argc, char** argv) {
   GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 200);
   grpc::testing::TestEnvironment env(argc, argv);
+  // The grpc_init is to cover the MAYBE_SKIP_TEST.
+  grpc_init();
   ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
 }
index 63a6897..626b5a5 100644 (file)
  *
  */
 
-#include <algorithm>
-#include <memory>
-#include <mutex>
-#include <random>
-#include <thread>
-
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpcpp/health_check_service_interface.h>
 #include <grpcpp/server.h>
 #include <grpcpp/server_builder.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#include <random>
+#include <thread>
 
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/gpr/env.h"
-
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/debugger_macros.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/end2end/test_service_impl.h"
-
-#include <gtest/gtest.h>
+#include "test/cpp/util/test_credentials_provider.h"
 
 #ifdef GPR_LINUX
 using grpc::testing::EchoRequest;
@@ -54,14 +54,20 @@ namespace grpc {
 namespace testing {
 namespace {
 
-class FlakyNetworkTest : public ::testing::Test {
+struct TestScenario {
+  TestScenario(const grpc::string& creds_type, const grpc::string& content)
+      : credentials_type(creds_type), message_content(content) {}
+  const grpc::string credentials_type;
+  const grpc::string message_content;
+};
+
+class FlakyNetworkTest : public ::testing::TestWithParam<TestScenario> {
  protected:
   FlakyNetworkTest()
       : server_host_("grpctest"),
         interface_("lo:1"),
         ipv4_address_("10.0.0.1"),
-        netmask_("/32"),
-        kRequestMessage_("🖖") {}
+        netmask_("/32") {}
 
   void InterfaceUp() {
     std::ostringstream cmd;
@@ -129,10 +135,11 @@ class FlakyNetworkTest : public ::testing::Test {
   void FlakeNetwork() {
     std::ostringstream cmd;
     // Emulate a flaky network connection over interface_. Add a delay of 100ms
-    // +/- 590ms, 3% packet loss, 1% duplicates and 0.1% corrupt packets.
+    // +/- 20ms, 0.1% packet loss, 1% duplicates and 0.01% corrupt packets.
     cmd << "tc qdisc replace dev " << interface_
-        << " root netem delay 100ms 50ms distribution normal loss 3% duplicate "
-           "1% corrupt 0.1% ";
+        << " root netem delay 100ms 20ms distribution normal loss 0.1% "
+           "duplicate "
+           "0.1% corrupt 0.01% ";
     std::system(cmd.str().c_str());
   }
 
@@ -172,7 +179,7 @@ class FlakyNetworkTest : public ::testing::Test {
     // ip6-looopback, but ipv6 support is not enabled by default in docker.
     port_ = SERVER_PORT;
 
-    server_.reset(new ServerData(port_));
+    server_.reset(new ServerData(port_, GetParam().credentials_type));
     server_->Start(server_host_);
   }
   void StopServer() { server_->Shutdown(); }
@@ -188,10 +195,11 @@ class FlakyNetworkTest : public ::testing::Test {
     if (lb_policy_name.size() > 0) {
       args.SetLoadBalancingPolicyName(lb_policy_name);
     }  // else, default to pick first
+    auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
+        GetParam().credentials_type, &args);
     std::ostringstream server_address;
     server_address << server_host_ << ":" << port_;
-    return CreateCustomChannel(server_address.str(),
-                               InsecureChannelCredentials(), args);
+    return CreateCustomChannel(server_address.str(), channel_creds, args);
   }
 
   bool SendRpc(
@@ -199,7 +207,8 @@ class FlakyNetworkTest : public ::testing::Test {
       int timeout_ms = 0, bool wait_for_ready = false) {
     auto response = std::unique_ptr<EchoResponse>(new EchoResponse());
     EchoRequest request;
-    request.set_message(kRequestMessage_);
+    auto& msg = GetParam().message_content;
+    request.set_message(msg);
     ClientContext context;
     if (timeout_ms > 0) {
       context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
@@ -211,22 +220,33 @@ class FlakyNetworkTest : public ::testing::Test {
     }
     Status status = stub->Echo(&context, request, response.get());
     auto ok = status.ok();
+    int stream_id = 0;
+    grpc_call* call = context.c_call();
+    if (call) {
+      grpc_chttp2_stream* stream = grpc_chttp2_stream_from_call(call);
+      if (stream) {
+        stream_id = stream->id;
+      }
+    }
     if (ok) {
-      gpr_log(GPR_DEBUG, "RPC returned %s\n", response->message().c_str());
+      gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id);
     } else {
-      gpr_log(GPR_DEBUG, "RPC failed: %s", status.error_message().c_str());
+      gpr_log(GPR_DEBUG, "RPC with stream_id %d failed: %s", stream_id,
+              status.error_message().c_str());
     }
     return ok;
   }
 
   struct ServerData {
     int port_;
+    const grpc::string creds_;
     std::unique_ptr<Server> server_;
     TestServiceImpl service_;
     std::unique_ptr<std::thread> thread_;
     bool server_ready_ = false;
 
-    explicit ServerData(int port) { port_ = port; }
+    ServerData(int port, const grpc::string& creds)
+        : port_(port), creds_(creds) {}
 
     void Start(const grpc::string& server_host) {
       gpr_log(GPR_INFO, "starting server on port %d", port_);
@@ -245,8 +265,9 @@ class FlakyNetworkTest : public ::testing::Test {
       std::ostringstream server_address;
       server_address << server_host << ":" << port_;
       ServerBuilder builder;
-      builder.AddListeningPort(server_address.str(),
-                               InsecureServerCredentials());
+      auto server_creds =
+          GetCredentialsProvider()->GetServerCredentials(creds_);
+      builder.AddListeningPort(server_address.str(), server_creds);
       builder.RegisterService(&service_);
       server_ = builder.BuildAndStart();
       std::lock_guard<std::mutex> lock(*mu);
@@ -291,11 +312,43 @@ class FlakyNetworkTest : public ::testing::Test {
   std::unique_ptr<ServerData> server_;
   const int SERVER_PORT = 32750;
   int port_;
-  const grpc::string kRequestMessage_;
 };
 
+std::vector<TestScenario> CreateTestScenarios() {
+  std::vector<TestScenario> scenarios;
+  std::vector<grpc::string> credentials_types;
+  std::vector<grpc::string> messages;
+
+  credentials_types.push_back(kInsecureCredentialsType);
+  auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList();
+  for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) {
+    credentials_types.push_back(*sec);
+  }
+
+  messages.push_back("🖖");
+  for (size_t k = 1; k < GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH / 1024; k *= 32) {
+    grpc::string big_msg;
+    for (size_t i = 0; i < k * 1024; ++i) {
+      char c = 'a' + (i % 26);
+      big_msg += c;
+    }
+    messages.push_back(big_msg);
+  }
+  for (auto cred = credentials_types.begin(); cred != credentials_types.end();
+       ++cred) {
+    for (auto msg = messages.begin(); msg != messages.end(); msg++) {
+      scenarios.emplace_back(*cred, *msg);
+    }
+  }
+
+  return scenarios;
+}
+
+INSTANTIATE_TEST_CASE_P(FlakyNetworkTest, FlakyNetworkTest,
+                        ::testing::ValuesIn(CreateTestScenarios()));
+
 // Network interface connected to server flaps
-TEST_F(FlakyNetworkTest, NetworkTransition) {
+TEST_P(FlakyNetworkTest, NetworkTransition) {
   const int kKeepAliveTimeMs = 1000;
   const int kKeepAliveTimeoutMs = 1000;
   ChannelArguments args;
@@ -336,7 +389,7 @@ TEST_F(FlakyNetworkTest, NetworkTransition) {
 }
 
 // Traffic to server server is blackholed temporarily with keepalives enabled
-TEST_F(FlakyNetworkTest, ServerUnreachableWithKeepalive) {
+TEST_P(FlakyNetworkTest, ServerUnreachableWithKeepalive) {
   const int kKeepAliveTimeMs = 1000;
   const int kKeepAliveTimeoutMs = 1000;
   const int kReconnectBackoffMs = 1000;
@@ -385,7 +438,7 @@ TEST_F(FlakyNetworkTest, ServerUnreachableWithKeepalive) {
 
 //
 // Traffic to server server is blackholed temporarily with keepalives disabled
-TEST_F(FlakyNetworkTest, ServerUnreachableNoKeepalive) {
+TEST_P(FlakyNetworkTest, ServerUnreachableNoKeepalive) {
   auto channel = BuildChannel("pick_first", ChannelArguments());
   auto stub = BuildStub(channel);
   // Channel should be in READY state after we send an RPC
@@ -411,7 +464,7 @@ TEST_F(FlakyNetworkTest, ServerUnreachableNoKeepalive) {
 }
 
 // Send RPCs over a flaky network connection
-TEST_F(FlakyNetworkTest, FlakyNetwork) {
+TEST_P(FlakyNetworkTest, FlakyNetwork) {
   const int kKeepAliveTimeMs = 1000;
   const int kKeepAliveTimeoutMs = 1000;
   const int kMessageCount = 100;
@@ -438,7 +491,7 @@ TEST_F(FlakyNetworkTest, FlakyNetwork) {
 }
 
 // Server is shutdown gracefully and restarted. Client keepalives are enabled
-TEST_F(FlakyNetworkTest, ServerRestartKeepaliveEnabled) {
+TEST_P(FlakyNetworkTest, ServerRestartKeepaliveEnabled) {
   const int kKeepAliveTimeMs = 1000;
   const int kKeepAliveTimeoutMs = 1000;
   ChannelArguments args;
@@ -468,7 +521,7 @@ TEST_F(FlakyNetworkTest, ServerRestartKeepaliveEnabled) {
 }
 
 // Server is shutdown gracefully and restarted. Client keepalives are enabled
-TEST_F(FlakyNetworkTest, ServerRestartKeepaliveDisabled) {
+TEST_P(FlakyNetworkTest, ServerRestartKeepaliveDisabled) {
   auto channel = BuildChannel("pick_first", ChannelArguments());
   auto stub = BuildStub(channel);
   // Channel should be in READY state after we send an RPC
index 50b1383..70c4434 100644 (file)
@@ -372,11 +372,7 @@ class GrpclbEnd2endTest : public ::testing::Test {
         num_backends_(num_backends),
         num_balancers_(num_balancers),
         client_load_reporting_interval_seconds_(
-            client_load_reporting_interval_seconds) {
-    // Make the backup poller poll very frequently in order to pick up
-    // updates from all the subchannels's FDs.
-    GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
-  }
+            client_load_reporting_interval_seconds) {}
 
   void SetUp() override {
     response_generator_ =
@@ -1994,6 +1990,9 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) {
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  // Make the backup poller poll very frequently in order to pick up
+  // updates from all the subchannels's FDs.
+  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
   grpc_init();
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
index 900f02b..6321c35 100644 (file)
@@ -48,7 +48,7 @@ void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel) {
   EchoResponse resp;
   string expected_resp = "";
   auto writer = stub->RequestStream(&ctx, &resp);
-  for (int i = 0; i < 10; i++) {
+  for (int i = 0; i < kNumStreamingMessages; i++) {
     writer->Write(req);
     expected_resp += "Hello";
   }
@@ -73,7 +73,7 @@ void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel) {
     EXPECT_EQ(resp.message(), "Hello");
     count++;
   }
-  ASSERT_EQ(count, 10);
+  ASSERT_EQ(count, kNumStreamingMessages);
   Status s = reader->Finish();
   EXPECT_EQ(s.ok(), true);
 }
@@ -85,7 +85,7 @@ void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
   EchoResponse resp;
   ctx.AddMetadata("testkey", "testvalue");
   auto stream = stub->BidiStream(&ctx);
-  for (auto i = 0; i < 10; i++) {
+  for (auto i = 0; i < kNumStreamingMessages; i++) {
     req.set_message("Hello" + std::to_string(i));
     stream->Write(req);
     stream->Read(&resp);
index 419845e..1cd1448 100644 (file)
@@ -152,6 +152,8 @@ class EchoTestServiceStreamingImpl : public EchoTestService::Service {
   }
 };
 
+constexpr int kNumStreamingMessages = 10;
+
 void MakeCall(const std::shared_ptr<Channel>& channel);
 
 void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel);
index c833a4f..1c52259 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <google/protobuf/arena.h>
 
+#include <grpc/impl/codegen/log.h>
 #include <gtest/gtest.h>
 
 #include <grpcpp/channel.h>
@@ -62,11 +63,9 @@ class CallbackTestServiceImpl
  public:
   explicit CallbackTestServiceImpl() {}
 
-  void SetFreeRequest() { free_request_ = true; }
-
   void SetAllocatorMutator(
-      std::function<void(void* allocator_state, const EchoRequest* req,
-                         EchoResponse* resp)>
+      std::function<void(experimental::RpcAllocatorState* allocator_state,
+                         const EchoRequest* req, EchoResponse* resp)>
           mutator) {
     allocator_mutator_ = mutator;
   }
@@ -75,18 +74,15 @@ class CallbackTestServiceImpl
             EchoResponse* response,
             experimental::ServerCallbackRpcController* controller) override {
     response->set_message(request->message());
-    if (free_request_) {
-      controller->FreeRequest();
-    } else if (allocator_mutator_) {
-      allocator_mutator_(controller->GetAllocatorState(), request, response);
+    if (allocator_mutator_) {
+      allocator_mutator_(controller->GetRpcAllocatorState(), request, response);
     }
     controller->Finish(Status::OK);
   }
 
  private:
-  bool free_request_ = false;
-  std::function<void(void* allocator_state, const EchoRequest* req,
-                     EchoResponse* resp)>
+  std::function<void(experimental::RpcAllocatorState* allocator_state,
+                     const EchoRequest* req, EchoResponse* resp)>
       allocator_mutator_;
 };
 
@@ -230,26 +226,44 @@ class SimpleAllocatorTest : public MessageAllocatorEnd2endTestBase {
   class SimpleAllocator
       : public experimental::MessageAllocator<EchoRequest, EchoResponse> {
    public:
-    void AllocateMessages(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
+    class MessageHolderImpl
+        : public experimental::MessageHolder<EchoRequest, EchoResponse> {
+     public:
+      MessageHolderImpl(int* request_deallocation_count,
+                        int* messages_deallocation_count)
+          : request_deallocation_count_(request_deallocation_count),
+            messages_deallocation_count_(messages_deallocation_count) {
+        set_request(new EchoRequest);
+        set_response(new EchoResponse);
+      }
+      void Release() override {
+        (*messages_deallocation_count_)++;
+        delete request();
+        delete response();
+        delete this;
+      }
+      void FreeRequest() override {
+        (*request_deallocation_count_)++;
+        delete request();
+        set_request(nullptr);
+      }
+
+      EchoRequest* ReleaseRequest() {
+        auto* ret = request();
+        set_request(nullptr);
+        return ret;
+      }
+
+     private:
+      int* request_deallocation_count_;
+      int* messages_deallocation_count_;
+    };
+    experimental::MessageHolder<EchoRequest, EchoResponse>* AllocateMessages()
+        override {
       allocation_count++;
-      info->request = new EchoRequest;
-      info->response = new EchoResponse;
-      info->allocator_state = info;
-    }
-    void DeallocateRequest(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
-      request_deallocation_count++;
-      delete info->request;
-      info->request = nullptr;
-    }
-    void DeallocateMessages(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
-      messages_deallocation_count++;
-      delete info->request;
-      delete info->response;
+      return new MessageHolderImpl(&request_deallocation_count,
+                                   &messages_deallocation_count);
     }
-
     int allocation_count = 0;
     int request_deallocation_count = 0;
     int messages_deallocation_count = 0;
@@ -272,7 +286,16 @@ TEST_P(SimpleAllocatorTest, RpcWithEarlyFreeRequest) {
   MAYBE_SKIP_TEST;
   const int kRpcCount = 10;
   std::unique_ptr<SimpleAllocator> allocator(new SimpleAllocator);
-  callback_service_.SetFreeRequest();
+  auto mutator = [](experimental::RpcAllocatorState* allocator_state,
+                    const EchoRequest* req, EchoResponse* resp) {
+    auto* info =
+        static_cast<SimpleAllocator::MessageHolderImpl*>(allocator_state);
+    EXPECT_EQ(req, info->request());
+    EXPECT_EQ(resp, info->response());
+    allocator_state->FreeRequest();
+    EXPECT_EQ(nullptr, info->request());
+  };
+  callback_service_.SetAllocatorMutator(mutator);
   CreateServer(allocator.get());
   ResetStub();
   SendRpcs(kRpcCount);
@@ -286,17 +309,15 @@ TEST_P(SimpleAllocatorTest, RpcWithReleaseRequest) {
   const int kRpcCount = 10;
   std::unique_ptr<SimpleAllocator> allocator(new SimpleAllocator);
   std::vector<EchoRequest*> released_requests;
-  auto mutator = [&released_requests](void* allocator_state,
-                                      const EchoRequest* req,
-                                      EchoResponse* resp) {
+  auto mutator = [&released_requests](
+                     experimental::RpcAllocatorState* allocator_state,
+                     const EchoRequest* req, EchoResponse* resp) {
     auto* info =
-        static_cast<experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>*>(
-            allocator_state);
-    EXPECT_EQ(req, info->request);
-    EXPECT_EQ(resp, info->response);
-    EXPECT_EQ(allocator_state, info->allocator_state);
-    released_requests.push_back(info->request);
-    info->request = nullptr;
+        static_cast<SimpleAllocator::MessageHolderImpl*>(allocator_state);
+    EXPECT_EQ(req, info->request());
+    EXPECT_EQ(resp, info->response());
+    released_requests.push_back(info->ReleaseRequest());
+    EXPECT_EQ(nullptr, info->request());
   };
   callback_service_.SetAllocatorMutator(mutator);
   CreateServer(allocator.get());
@@ -316,30 +337,27 @@ class ArenaAllocatorTest : public MessageAllocatorEnd2endTestBase {
   class ArenaAllocator
       : public experimental::MessageAllocator<EchoRequest, EchoResponse> {
    public:
-    void AllocateMessages(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
+    class MessageHolderImpl
+        : public experimental::MessageHolder<EchoRequest, EchoResponse> {
+     public:
+      MessageHolderImpl() {
+        set_request(
+            google::protobuf::Arena::CreateMessage<EchoRequest>(&arena_));
+        set_response(
+            google::protobuf::Arena::CreateMessage<EchoResponse>(&arena_));
+      }
+      void Release() override { delete this; }
+      void FreeRequest() override { GPR_ASSERT(0); }
+
+     private:
+      google::protobuf::Arena arena_;
+    };
+    experimental::MessageHolder<EchoRequest, EchoResponse>* AllocateMessages()
+        override {
       allocation_count++;
-      auto* arena = new google::protobuf::Arena;
-      info->allocator_state = arena;
-      info->request =
-          google::protobuf::Arena::CreateMessage<EchoRequest>(arena);
-      info->response =
-          google::protobuf::Arena::CreateMessage<EchoResponse>(arena);
-    }
-    void DeallocateRequest(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
-      GPR_ASSERT(0);
+      return new MessageHolderImpl;
     }
-    void DeallocateMessages(
-        experimental::RpcAllocatorInfo<EchoRequest, EchoResponse>* info) {
-      deallocation_count++;
-      auto* arena =
-          static_cast<google::protobuf::Arena*>(info->allocator_state);
-      delete arena;
-    }
-
     int allocation_count = 0;
-    int deallocation_count = 0;
   };
 };
 
@@ -351,7 +369,6 @@ TEST_P(ArenaAllocatorTest, SimpleRpc) {
   ResetStub();
   SendRpcs(kRpcCount);
   EXPECT_EQ(kRpcCount, allocator->allocation_count);
-  EXPECT_EQ(kRpcCount, allocator->deallocation_count);
 }
 
 std::vector<TestScenario> CreateTestScenarios(bool test_insecure) {
diff --git a/test/cpp/end2end/port_sharing_end2end_test.cc b/test/cpp/end2end/port_sharing_end2end_test.cc
new file mode 100644 (file)
index 0000000..4f30290
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ *
+ * Copyright 2019 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 <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <gtest/gtest.h>
+
+#include <mutex>
+#include <thread>
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/port.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/security/credentials/credentials.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/core/util/test_tcp_server.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/test_credentials_provider.h"
+
+#ifdef GRPC_POSIX_SOCKET_TCP_SERVER
+
+#include "src/core/lib/iomgr/tcp_posix.h"
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class TestScenario {
+ public:
+  TestScenario(bool server_port, bool pending_data,
+               const grpc::string& creds_type)
+      : server_has_port(server_port),
+        queue_pending_data(pending_data),
+        credentials_type(creds_type) {}
+  void Log() const;
+  // server has its own port or not
+  bool server_has_port;
+  // whether tcp server should read some data before handoff
+  bool queue_pending_data;
+  const grpc::string credentials_type;
+};
+
+static std::ostream& operator<<(std::ostream& out,
+                                const TestScenario& scenario) {
+  return out << "TestScenario{server_has_port="
+             << (scenario.server_has_port ? "true" : "false")
+             << ", queue_pending_data="
+             << (scenario.queue_pending_data ? "true" : "false")
+             << ", credentials='" << scenario.credentials_type << "'}";
+}
+
+void TestScenario::Log() const {
+  std::ostringstream out;
+  out << *this;
+  gpr_log(GPR_ERROR, "%s", out.str().c_str());
+}
+
+// Set up a test tcp server which is in charge of accepting connections and
+// handing off the connections as fds.
+class TestTcpServer {
+ public:
+  TestTcpServer()
+      : shutdown_(false),
+        queue_data_(false),
+        port_(grpc_pick_unused_port_or_die()) {
+    std::ostringstream server_address;
+    server_address << "localhost:" << port_;
+    address_ = server_address.str();
+    test_tcp_server_init(&tcp_server_, &TestTcpServer::OnConnect, this);
+    GRPC_CLOSURE_INIT(&on_fd_released_, &TestTcpServer::OnFdReleased, this,
+                      grpc_schedule_on_exec_ctx);
+  }
+
+  ~TestTcpServer() {
+    running_thread_.join();
+    test_tcp_server_destroy(&tcp_server_);
+    grpc_recycle_unused_port(port_);
+  }
+
+  // Read some data before handing off the connection.
+  void SetQueueData() { queue_data_ = true; }
+
+  void Start() {
+    test_tcp_server_start(&tcp_server_, port_);
+    gpr_log(GPR_INFO, "Test TCP server started at %s", address_.c_str());
+  }
+
+  const grpc::string& address() { return address_; }
+
+  void SetAcceptor(
+      std::unique_ptr<experimental::ExternalConnectionAcceptor> acceptor) {
+    connection_acceptor_ = std::move(acceptor);
+  }
+
+  void Run() {
+    running_thread_ = std::thread([this]() {
+      while (true) {
+        {
+          std::lock_guard<std::mutex> lock(mu_);
+          if (shutdown_) {
+            return;
+          }
+        }
+        test_tcp_server_poll(&tcp_server_, 1);
+      }
+    });
+  }
+
+  void Shutdown() {
+    std::lock_guard<std::mutex> lock(mu_);
+    shutdown_ = true;
+  }
+
+  static void OnConnect(void* arg, grpc_endpoint* tcp,
+                        grpc_pollset* accepting_pollset,
+                        grpc_tcp_server_acceptor* acceptor) {
+    auto* self = static_cast<TestTcpServer*>(arg);
+    self->OnConnect(tcp, accepting_pollset, acceptor);
+  }
+
+  static void OnFdReleased(void* arg, grpc_error* err) {
+    auto* self = static_cast<TestTcpServer*>(arg);
+    self->OnFdReleased(err);
+  }
+
+ private:
+  void OnConnect(grpc_endpoint* tcp, grpc_pollset* accepting_pollset,
+                 grpc_tcp_server_acceptor* acceptor) {
+    char* peer = grpc_endpoint_get_peer(tcp);
+    gpr_log(GPR_INFO, "Got incoming connection! from %s", peer);
+    gpr_free(peer);
+    EXPECT_FALSE(acceptor->external_connection);
+    listener_fd_ = grpc_tcp_server_port_fd(
+        acceptor->from_server, acceptor->port_index, acceptor->fd_index);
+    gpr_free(acceptor);
+    grpc_tcp_destroy_and_release_fd(tcp, &fd_, &on_fd_released_);
+  }
+
+  void OnFdReleased(grpc_error* err) {
+    EXPECT_EQ(GRPC_ERROR_NONE, err);
+    experimental::ExternalConnectionAcceptor::NewConnectionParameters p;
+    p.listener_fd = listener_fd_;
+    p.fd = fd_;
+    if (queue_data_) {
+      char buf[1024];
+      ssize_t read_bytes = 0;
+      while (read_bytes <= 0) {
+        read_bytes = read(fd_, buf, 1024);
+      }
+      Slice data(buf, read_bytes);
+      p.read_buffer = ByteBuffer(&data, 1);
+    }
+    gpr_log(GPR_INFO, "Handing off fd %d with data size %d from listener fd %d",
+            fd_, static_cast<int>(p.read_buffer.Length()), listener_fd_);
+    connection_acceptor_->HandleNewConnection(&p);
+  }
+
+  std::mutex mu_;
+  bool shutdown_;
+
+  int listener_fd_ = -1;
+  int fd_ = -1;
+  bool queue_data_ = false;
+
+  grpc_closure on_fd_released_;
+  std::thread running_thread_;
+  int port_ = -1;
+  grpc::string address_;
+  std::unique_ptr<experimental::ExternalConnectionAcceptor>
+      connection_acceptor_;
+  test_tcp_server tcp_server_;
+};
+
+class PortSharingEnd2endTest : public ::testing::TestWithParam<TestScenario> {
+ protected:
+  PortSharingEnd2endTest() : is_server_started_(false), first_picked_port_(0) {
+    GetParam().Log();
+  }
+
+  void SetUp() override {
+    if (GetParam().queue_pending_data) {
+      tcp_server1_.SetQueueData();
+      tcp_server2_.SetQueueData();
+    }
+    tcp_server1_.Start();
+    tcp_server2_.Start();
+    ServerBuilder builder;
+    if (GetParam().server_has_port) {
+      int port = grpc_pick_unused_port_or_die();
+      first_picked_port_ = port;
+      server_address_ << "localhost:" << port;
+      auto creds = GetCredentialsProvider()->GetServerCredentials(
+          GetParam().credentials_type);
+      builder.AddListeningPort(server_address_.str(), creds);
+      gpr_log(GPR_INFO, "gRPC server listening on %s",
+              server_address_.str().c_str());
+    }
+    auto server_creds = GetCredentialsProvider()->GetServerCredentials(
+        GetParam().credentials_type);
+    auto acceptor1 = builder.experimental().AddExternalConnectionAcceptor(
+        ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD,
+        server_creds);
+    tcp_server1_.SetAcceptor(std::move(acceptor1));
+    auto acceptor2 = builder.experimental().AddExternalConnectionAcceptor(
+        ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD,
+        server_creds);
+    tcp_server2_.SetAcceptor(std::move(acceptor2));
+    builder.RegisterService(&service_);
+    server_ = builder.BuildAndStart();
+    is_server_started_ = true;
+
+    tcp_server1_.Run();
+    tcp_server2_.Run();
+  }
+
+  void TearDown() override {
+    tcp_server1_.Shutdown();
+    tcp_server2_.Shutdown();
+    if (is_server_started_) {
+      server_->Shutdown();
+    }
+    if (first_picked_port_ > 0) {
+      grpc_recycle_unused_port(first_picked_port_);
+    }
+  }
+
+  void ResetStubs() {
+    EXPECT_TRUE(is_server_started_);
+    ChannelArguments args;
+    args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
+    auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
+        GetParam().credentials_type, &args);
+    channel_handoff1_ =
+        CreateCustomChannel(tcp_server1_.address(), channel_creds, args);
+    stub_handoff1_ = EchoTestService::NewStub(channel_handoff1_);
+    channel_handoff2_ =
+        CreateCustomChannel(tcp_server2_.address(), channel_creds, args);
+    stub_handoff2_ = EchoTestService::NewStub(channel_handoff2_);
+    if (GetParam().server_has_port) {
+      ChannelArguments direct_args;
+      direct_args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
+      auto direct_creds = GetCredentialsProvider()->GetChannelCredentials(
+          GetParam().credentials_type, &direct_args);
+      channel_direct_ =
+          CreateCustomChannel(server_address_.str(), direct_creds, direct_args);
+      stub_direct_ = EchoTestService::NewStub(channel_direct_);
+    }
+  }
+
+  bool is_server_started_;
+  // channel/stub to the test tcp server, the connection will be handed to the
+  // grpc server.
+  std::shared_ptr<Channel> channel_handoff1_;
+  std::unique_ptr<EchoTestService::Stub> stub_handoff1_;
+  std::shared_ptr<Channel> channel_handoff2_;
+  std::unique_ptr<EchoTestService::Stub> stub_handoff2_;
+  // channel/stub to talk to the grpc server directly, if applicable.
+  std::shared_ptr<Channel> channel_direct_;
+  std::unique_ptr<EchoTestService::Stub> stub_direct_;
+  std::unique_ptr<Server> server_;
+  std::ostringstream server_address_;
+  TestServiceImpl service_;
+  TestTcpServer tcp_server1_;
+  TestTcpServer tcp_server2_;
+  int first_picked_port_;
+};
+
+static void SendRpc(EchoTestService::Stub* stub, int num_rpcs) {
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello hello hello hello");
+
+  for (int i = 0; i < num_rpcs; ++i) {
+    ClientContext context;
+    Status s = stub->Echo(&context, request, &response);
+    EXPECT_EQ(response.message(), request.message());
+    EXPECT_TRUE(s.ok());
+  }
+}
+
+std::vector<TestScenario> CreateTestScenarios() {
+  std::vector<TestScenario> scenarios;
+  std::vector<grpc::string> credentials_types;
+  credentials_types = GetCredentialsProvider()->GetSecureCredentialsTypeList();
+  // Only allow insecure credentials type when it is registered with the
+  // provider. User may create providers that do not have insecure.
+  if (GetCredentialsProvider()->GetChannelCredentials(kInsecureCredentialsType,
+                                                      nullptr) != nullptr) {
+    credentials_types.push_back(kInsecureCredentialsType);
+  }
+
+  GPR_ASSERT(!credentials_types.empty());
+  for (const auto& cred : credentials_types) {
+    for (auto server_has_port : {true, false}) {
+      for (auto queue_pending_data : {true, false}) {
+        scenarios.emplace_back(server_has_port, queue_pending_data, cred);
+      }
+    }
+  }
+  return scenarios;
+}
+
+TEST_P(PortSharingEnd2endTest, HandoffAndDirectCalls) {
+  ResetStubs();
+  SendRpc(stub_handoff1_.get(), 5);
+  if (GetParam().server_has_port) {
+    SendRpc(stub_direct_.get(), 5);
+  }
+}
+
+TEST_P(PortSharingEnd2endTest, MultipleHandoff) {
+  for (int i = 0; i < 3; i++) {
+    ResetStubs();
+    SendRpc(stub_handoff2_.get(), 1);
+  }
+}
+
+TEST_P(PortSharingEnd2endTest, TwoHandoffPorts) {
+  for (int i = 0; i < 3; i++) {
+    ResetStubs();
+    SendRpc(stub_handoff1_.get(), 5);
+    SendRpc(stub_handoff2_.get(), 5);
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(PortSharingEnd2end, PortSharingEnd2endTest,
+                        ::testing::ValuesIn(CreateTestScenarios()));
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_POSIX_SOCKET_TCP_SERVER
+
+int main(int argc, char** argv) {
+  grpc::testing::TestEnvironment env(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
index 68103f7..34409fe 100644 (file)
@@ -120,7 +120,9 @@ class LoggingInterceptor : public experimental::Interceptor {
             experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
       EchoResponse* resp =
           static_cast<EchoResponse*>(methods->GetRecvMessage());
-      EXPECT_TRUE(resp->message().find("Hello") == 0);
+      if (resp != nullptr) {
+        EXPECT_TRUE(resp->message().find("Hello") == 0);
+      }
     }
     if (methods->QueryInterceptionHookPoint(
             experimental::InterceptionHookPoints::POST_RECV_CLOSE)) {
index 2d05fd4..8bf4a7c 100644 (file)
@@ -36,6 +36,7 @@
 #include <grpcpp/impl/codegen/sync.h>
 #include <grpcpp/server.h>
 #include <grpcpp/server_builder.h>
+#include <grpcpp/support/validate_service_config.h>
 
 #include "src/core/ext/filters/client_channel/backup_poller.h"
 #include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
@@ -116,11 +117,7 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
       : 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_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
-  }
+            grpc_fake_transport_security_credentials_create())) {}
 
   void SetUp() override {
     grpc_init();
@@ -231,12 +228,27 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
 
   std::shared_ptr<Channel> BuildChannelWithDefaultServiceConfig() {
     ChannelArguments args;
+    EXPECT_THAT(grpc::experimental::ValidateServiceConfigJSON(
+                    ValidDefaultServiceConfig()),
+                ::testing::StrEq(""));
     args.SetServiceConfigJSON(ValidDefaultServiceConfig());
     args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
                     response_generator_.get());
     return ::grpc::CreateCustomChannel("fake:///", creds_, args);
   }
 
+  std::shared_ptr<Channel> BuildChannelWithInvalidDefaultServiceConfig() {
+    ChannelArguments args;
+    EXPECT_THAT(
+        grpc::experimental::ValidateServiceConfigJSON(
+            InvalidDefaultServiceConfig()),
+        ::testing::HasSubstr("failed to parse JSON for service config"));
+    args.SetServiceConfigJSON(InvalidDefaultServiceConfig());
+    args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
+                    response_generator_.get());
+    return ::grpc::CreateCustomChannel("fake:///", creds_, args);
+  }
+
   bool SendRpc(
       const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
       EchoResponse* response = nullptr, int timeout_ms = 1000,
@@ -402,7 +414,7 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
   }
 
   const char* InvalidDefaultServiceConfig() {
-    return "{\"version\": \"invalid_default\"}";
+    return "{\"version\": \"invalid_default\"";
   }
 
   const grpc::string server_host_;
@@ -549,11 +561,59 @@ TEST_F(ServiceConfigEnd2endTest,
   CheckRpcSendFailure(stub);
 }
 
+TEST_F(ServiceConfigEnd2endTest, InvalidDefaultServiceConfigTest) {
+  StartServers(1);
+  auto channel = BuildChannelWithInvalidDefaultServiceConfig();
+  auto stub = BuildStub(channel);
+  // An invalid default service config results in a lame channel which fails all
+  // RPCs
+  CheckRpcSendFailure(stub);
+}
+
+TEST_F(ServiceConfigEnd2endTest,
+       InvalidDefaultServiceConfigTestWithValidServiceConfig) {
+  StartServers(1);
+  auto channel = BuildChannelWithInvalidDefaultServiceConfig();
+  auto stub = BuildStub(channel);
+  CheckRpcSendFailure(stub);
+  // An invalid default service config results in a lame channel which fails all
+  // RPCs
+  SetNextResolutionValidServiceConfig(GetServersPorts());
+  CheckRpcSendFailure(stub);
+}
+
+TEST_F(ServiceConfigEnd2endTest,
+       InvalidDefaultServiceConfigTestWithInvalidServiceConfig) {
+  StartServers(1);
+  auto channel = BuildChannelWithInvalidDefaultServiceConfig();
+  auto stub = BuildStub(channel);
+  CheckRpcSendFailure(stub);
+  // An invalid default service config results in a lame channel which fails all
+  // RPCs
+  SetNextResolutionInvalidServiceConfig(GetServersPorts());
+  CheckRpcSendFailure(stub);
+}
+
+TEST_F(ServiceConfigEnd2endTest,
+       InvalidDefaultServiceConfigTestWithNoServiceConfig) {
+  StartServers(1);
+  auto channel = BuildChannelWithInvalidDefaultServiceConfig();
+  auto stub = BuildStub(channel);
+  CheckRpcSendFailure(stub);
+  // An invalid default service config results in a lame channel which fails all
+  // RPCs
+  SetNextResolutionNoServiceConfig(GetServersPorts());
+  CheckRpcSendFailure(stub);
+}
+
 }  // namespace
 }  // namespace testing
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  // Make the backup poller poll very frequently in order to pick up
+  // updates from all the subchannels's FDs.
+  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
   ::testing::InitGoogleTest(&argc, argv);
   grpc::testing::TestEnvironment env(argc, argv);
   const auto result = RUN_ALL_TESTS();
index 0801e30..5898527 100644 (file)
@@ -54,6 +54,7 @@ Status HealthCheckServiceImpl::Watch(
       }
       if (response.status() != last_state) {
         writer->Write(response, ::grpc::WriteOptions());
+        last_state = response.status();
       }
     }
     gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
index b876e06..eac6f32 100644 (file)
@@ -368,11 +368,7 @@ class XdsEnd2endTest : public ::testing::Test {
         num_backends_(num_backends),
         num_balancers_(num_balancers),
         client_load_reporting_interval_seconds_(
-            client_load_reporting_interval_seconds) {
-    // Make the backup poller poll very frequently in order to pick up
-    // updates from all the subchannels's FDs.
-    GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
-  }
+            client_load_reporting_interval_seconds) {}
 
   void SetUp() override {
     response_generator_ =
@@ -1015,6 +1011,22 @@ TEST_F(SingleBalancerTest, FallbackEarlyWhenBalancerCallFails) {
                  /* wait_for_ready */ false);
 }
 
+TEST_F(SingleBalancerTest, FallbackIfResponseReceivedButChildNotReady) {
+  const int kFallbackTimeoutMs = 500 * grpc_test_slowdown_factor();
+  ResetStub(kFallbackTimeoutMs);
+  SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str());
+  SetNextResolutionForLbChannelAllBalancers();
+  // Send a serverlist that only contains an unreachable backend before fallback
+  // timeout.
+  ScheduleResponseForBalancer(0,
+                              BalancerServiceImpl::BuildResponseForBackends(
+                                  {grpc_pick_unused_port_or_die()}, {}),
+                              0);
+  // Because no child policy is ready before fallback timeout, we enter fallback
+  // mode.
+  WaitForBackend(0);
+}
+
 TEST_F(SingleBalancerTest, FallbackModeIsExitedWhenBalancerSaysToDropAllCalls) {
   // Return an unreachable balancer and one fallback backend.
   SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str());
@@ -1389,6 +1401,9 @@ class SingleBalancerWithClientLoadReportingTest : public XdsEnd2endTest {
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  // Make the backup poller poll very frequently in order to pick up
+  // updates from all the subchannels's FDs.
+  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
   grpc_init();
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
index 6cf4719..802302b 100644 (file)
@@ -16,7 +16,10 @@ licenses(["notice"])  # Apache v2
 
 load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package")
 
-grpc_package(name = "test/cpp/interop")
+grpc_package(
+    name = "test/cpp/interop",
+    visibility = "public",
+)
 
 grpc_cc_library(
     name = "server_helper_lib",
@@ -104,6 +107,20 @@ grpc_cc_binary(
 )
 
 grpc_cc_binary(
+    name = "metrics_client",
+    srcs = ["metrics_client.cc"],
+    external_deps = [
+        "gflags",
+    ],
+    language = "C++",
+    deps = [
+        "//:grpc++",
+        "//test/cpp/util:metrics_server_lib",
+        "//test/cpp/util:test_config",
+    ],
+)
+
+grpc_cc_binary(
     name = "reconnect_interop_client",
     srcs = [
         "reconnect_interop_client.cc",
@@ -153,6 +170,7 @@ grpc_cc_test(
     external_deps = [
         "gflags",
     ],
+    tags = ["no_windows"],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -161,5 +179,4 @@ grpc_cc_test(
         "//test/cpp/util:test_config",
         "//test/cpp/util:test_util",
     ],
-    tags = ["no_windows"],
 )
index 6e844a6..d9424f2 100644 (file)
@@ -39,85 +39,85 @@ grpc_cc_library(
     external_deps = [
         "benchmark",
     ],
+    tags = ["no_windows"],
     deps = [
         "//:grpc++_unsecure",
         "//src/proto/grpc/testing:echo_proto",
         "//test/core/util:grpc_test_util_unsecure",
         "//test/cpp/util:test_config",
     ],
-    tags = ["no_windows"],
 )
 
 grpc_cc_binary(
     name = "bm_closure",
     testonly = 1,
     srcs = ["bm_closure.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_alarm",
     testonly = 1,
     srcs = ["bm_alarm.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_arena",
     testonly = 1,
     srcs = ["bm_arena.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_byte_buffer",
     testonly = 1,
     srcs = ["bm_byte_buffer.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_channel",
     testonly = 1,
     srcs = ["bm_channel.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_call_create",
     testonly = 1,
     srcs = ["bm_call_create.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_cq",
     testonly = 1,
     srcs = ["bm_cq.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_cq_multiple_threads",
     testonly = 1,
     srcs = ["bm_cq_multiple_threads.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_error",
     testonly = 1,
     srcs = ["bm_error.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_library(
@@ -126,8 +126,8 @@ grpc_cc_library(
     hdrs = [
         "fullstack_streaming_ping_pong.h",
     ],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
@@ -136,8 +136,8 @@ grpc_cc_binary(
     srcs = [
         "bm_fullstack_streaming_ping_pong.cc",
     ],
-    deps = [":fullstack_streaming_ping_pong_h"],
     tags = ["no_windows"],
+    deps = [":fullstack_streaming_ping_pong_h"],
 )
 
 grpc_cc_library(
@@ -155,16 +155,16 @@ grpc_cc_binary(
     srcs = [
         "bm_fullstack_streaming_pump.cc",
     ],
-    deps = [":fullstack_streaming_pump_h"],
     tags = ["no_windows"],
+    deps = [":fullstack_streaming_pump_h"],
 )
 
 grpc_cc_binary(
     name = "bm_fullstack_trickle",
     testonly = 1,
     srcs = ["bm_fullstack_trickle.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_library(
@@ -182,24 +182,24 @@ grpc_cc_binary(
     srcs = [
         "bm_fullstack_unary_ping_pong.cc",
     ],
-    deps = [":fullstack_unary_ping_pong_h"],
     tags = ["no_windows"],
+    deps = [":fullstack_unary_ping_pong_h"],
 )
 
 grpc_cc_binary(
     name = "bm_metadata",
     testonly = 1,
     srcs = ["bm_metadata.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
     name = "bm_chttp2_hpack",
     testonly = 1,
     srcs = ["bm_chttp2_hpack.cc"],
-    deps = [":helpers"],
     tags = ["no_windows"],
+    deps = [":helpers"],
 )
 
 grpc_cc_binary(
@@ -218,6 +218,65 @@ grpc_cc_binary(
     name = "bm_timer",
     testonly = 1,
     srcs = ["bm_timer.cc"],
+    tags = ["no_windows"],
     deps = [":helpers"],
+)
+
+grpc_cc_library(
+    name = "bm_callback_test_service_impl",
+    testonly = 1,
+    srcs = ["callback_test_service.cc"],
+    hdrs = ["callback_test_service.h"],
+    external_deps = [
+        "benchmark",
+    ],
+    deps = [
+        ":helpers",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/cpp/util:test_util",
+    ],
+)
+
+grpc_cc_library(
+    name = "callback_unary_ping_pong_h",
+    testonly = 1,
+    hdrs = [
+        "callback_unary_ping_pong.h",
+    ],
+    deps = [
+        ":bm_callback_test_service_impl",
+        ":helpers",
+    ],
+)
+
+grpc_cc_binary(
+    name = "bm_callback_unary_ping_pong",
+    testonly = 1,
+    srcs = [
+        "bm_callback_unary_ping_pong.cc",
+    ],
+    tags = ["no_windows"],
+    deps = [":callback_unary_ping_pong_h"],
+)
+
+grpc_cc_library(
+    name = "callback_streaming_ping_pong_h",
+    testonly = 1,
+    hdrs = [
+        "callback_streaming_ping_pong.h",
+    ],
+    deps = [
+        ":bm_callback_test_service_impl",
+        ":helpers",
+    ],
+)
+
+grpc_cc_binary(
+    name = "bm_callback_streaming_ping_pong",
+    testonly = 1,
+    srcs = [
+        "bm_callback_streaming_ping_pong.cc",
+    ],
     tags = ["no_windows"],
+    deps = [":callback_streaming_ping_pong_h"],
 )
diff --git a/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc
new file mode 100644 (file)
index 0000000..cde3eb2
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2019 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/microbenchmarks/callback_streaming_ping_pong.h"
+#include "test/cpp/util/test_config.h"
+
+namespace grpc {
+namespace testing {
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use
+// internal microbenchmarking tooling
+static void StreamingPingPongMsgSizeArgs(benchmark::internal::Benchmark* b) {
+  // base case: 0 byte ping-pong msgs
+  b->Args({0, 1});
+  b->Args({0, 2});
+
+  for (int msg_size = 1; msg_size <= 128 * 1024 * 1024; msg_size *= 8) {
+    b->Args({msg_size, 1});
+    b->Args({msg_size, 2});
+  }
+}
+
+// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use
+// internal microbenchmarking tooling
+static void StreamingPingPongMsgsNumberArgs(benchmark::internal::Benchmark* b) {
+  for (int msg_number = 1; msg_number <= 256 * 1024; msg_number *= 8) {
+    b->Args({0, msg_number});
+    b->Args({1024, msg_number});
+  }
+}
+
+// Streaming with different message size
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(StreamingPingPongMsgSizeArgs);
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, MinInProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(StreamingPingPongMsgSizeArgs);
+
+// Streaming with different message number
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(StreamingPingPongMsgsNumberArgs);
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, MinInProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(StreamingPingPongMsgsNumberArgs);
+
+// Client context with different metadata
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
+                   NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
+                   NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
+    ->Args({0, 1});
+
+// Server context with different metadata
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
+    ->Args({0, 1});
+BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
+    ->Args({0, 1});
+
+}  // namespace testing
+}  // namespace grpc
+
+// Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
+// and others do not. This allows us to support both modes.
+namespace benchmark {
+void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
+}  // namespace benchmark
+
+int main(int argc, char** argv) {
+  LibraryInitializer libInit;
+  ::benchmark::Initialize(&argc, argv);
+  ::grpc::testing::InitTest(&argc, &argv, false);
+  benchmark::RunTheBenchmarksNamespaced();
+  return 0;
+}
diff --git a/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc
new file mode 100644 (file)
index 0000000..4ee7752
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2019 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/microbenchmarks/callback_unary_ping_pong.h"
+#include "test/cpp/util/test_config.h"
+
+namespace grpc {
+namespace testing {
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use
+// internal microbenchmarking tooling
+static void SweepSizesArgs(benchmark::internal::Benchmark* b) {
+  b->Args({0, 0});
+  for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
+    // First argument is the message size of request
+    // Second argument is the message size of response
+    b->Args({i, 0});
+    b->Args({0, i});
+    b->Args({i, i});
+  }
+}
+
+// Unary ping pong with different message size of request and response
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, MinInProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(SweepSizesArgs);
+
+// Client context with different metadata
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
+                   NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
+                   NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
+    ->Args({0, 0});
+
+// Server context with different metadata
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
+    ->Args({0, 0});
+}  // namespace testing
+}  // namespace grpc
+
+// Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
+// and others do not. This allows us to support both modes.
+namespace benchmark {
+void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
+}  // namespace benchmark
+
+int main(int argc, char** argv) {
+  LibraryInitializer libInit;
+  ::benchmark::Initialize(&argc, argv);
+  ::grpc::testing::InitTest(&argc, &argv, false);
+  benchmark::RunTheBenchmarksNamespaced();
+  return 0;
+}
index 0550458..3df979e 100644 (file)
@@ -259,18 +259,21 @@ static void BM_StreamCreateDestroy(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
   Fixture f(grpc::ChannelArguments(), true);
-  Stream s(&f);
+  auto* s = new Stream(&f);
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload op_payload(nullptr);
   memset(&op, 0, sizeof(op));
   op.cancel_stream = true;
   op.payload = &op_payload;
   op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
-  std::unique_ptr<Closure> next = MakeClosure([&](grpc_error* error) {
-    if (!state.KeepRunning()) return;
-    s.Init(state);
-    s.Op(&op);
-    s.DestroyThen(next.get());
+  std::unique_ptr<Closure> next = MakeClosure([&, s](grpc_error* error) {
+    if (!state.KeepRunning()) {
+      delete s;
+      return;
+    }
+    s->Init(state);
+    s->Op(&op);
+    s->DestroyThen(next.get());
   });
   GRPC_CLOSURE_RUN(next.get(), GRPC_ERROR_NONE);
   f.FlushExecCtx();
@@ -305,7 +308,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
   Fixture f(grpc::ChannelArguments(), true);
-  Stream s(&f);
+  auto* s = new Stream(&f);
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload op_payload(nullptr);
   std::unique_ptr<Closure> start;
@@ -327,21 +330,24 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
   }
 
   f.FlushExecCtx();
-  start = MakeClosure([&](grpc_error* error) {
-    if (!state.KeepRunning()) return;
-    s.Init(state);
+  start = MakeClosure([&, s](grpc_error* error) {
+    if (!state.KeepRunning()) {
+      delete s;
+      return;
+    }
+    s->Init(state);
     reset_op();
     op.on_complete = done.get();
     op.send_initial_metadata = true;
     op.payload->send_initial_metadata.send_initial_metadata = &b;
-    s.Op(&op);
+    s->Op(&op);
   });
   done = MakeClosure([&](grpc_error* error) {
     reset_op();
     op.cancel_stream = true;
     op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
-    s.Op(&op);
-    s.DestroyThen(start.get());
+    s->Op(&op);
+    s->DestroyThen(start.get());
   });
   GRPC_CLOSURE_SCHED(start.get(), GRPC_ERROR_NONE);
   f.FlushExecCtx();
@@ -355,8 +361,8 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
   Fixture f(grpc::ChannelArguments(), true);
-  Stream s(&f);
-  s.Init(state);
+  auto* s = new Stream(&f);
+  s->Init(state);
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload op_payload(nullptr);
   auto reset_op = [&]() {
@@ -367,15 +373,15 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
     if (!state.KeepRunning()) return;
     reset_op();
     op.on_complete = c.get();
-    s.Op(&op);
+    s->Op(&op);
   });
   GRPC_CLOSURE_SCHED(c.get(), GRPC_ERROR_NONE);
   f.FlushExecCtx();
   reset_op();
   op.cancel_stream = true;
   op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
-  s.Op(&op);
-  s.DestroyThen(MakeOnceClosure([](grpc_error* error) {}));
+  s->Op(&op);
+  s->DestroyThen(MakeOnceClosure([s](grpc_error* error) { delete s; }));
   f.FlushExecCtx();
   track_counters.Finish(state);
 }
@@ -387,7 +393,7 @@ static void BM_TransportStreamSend(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
   Fixture f(grpc::ChannelArguments(), true);
-  auto s = std::unique_ptr<Stream>(new Stream(&f));
+  auto* s = new Stream(&f);
   s->Init(state);
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload op_payload(nullptr);
@@ -450,9 +456,8 @@ static void BM_TransportStreamSend(benchmark::State& state) {
   op.cancel_stream = true;
   op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
   s->Op(&op);
-  s->DestroyThen(MakeOnceClosure([](grpc_error* error) {}));
+  s->DestroyThen(MakeOnceClosure([s](grpc_error* error) { delete s; }));
   f.FlushExecCtx();
-  s.reset();
   track_counters.Finish(state);
   grpc_metadata_batch_destroy(&b);
   grpc_slice_unref(send_slice);
@@ -520,8 +525,8 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
   Fixture f(grpc::ChannelArguments(), true);
-  Stream s(&f);
-  s.Init(state);
+  auto* s = new Stream(&f);
+  s->Init(state);
   grpc_transport_stream_op_batch_payload op_payload(nullptr);
   grpc_transport_stream_op_batch op;
   grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_stream;
@@ -557,7 +562,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   std::unique_ptr<Closure> c = MakeClosure([&](grpc_error* error) {
     if (!state.KeepRunning()) return;
     // force outgoing window to be yuge
-    s.chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
+    s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
     f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
     received = 0;
     reset_op();
@@ -565,7 +570,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
     op.recv_message = true;
     op.payload->recv_message.recv_message = &recv_stream;
     op.payload->recv_message.recv_message_ready = drain_start.get();
-    s.Op(&op);
+    s->Op(&op);
     f.PushInput(grpc_slice_ref(incoming_data));
   });
 
@@ -606,7 +611,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   op.payload->recv_initial_metadata.recv_initial_metadata_ready =
       do_nothing.get();
   op.on_complete = c.get();
-  s.Op(&op);
+  s->Op(&op);
   f.PushInput(SLICE_FROM_BUFFER(
       "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
       // Generated using:
@@ -624,12 +629,12 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   reset_op();
   op.cancel_stream = true;
   op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
-  s.Op(&op);
-  s.DestroyThen(MakeOnceClosure([](grpc_error* error) {}));
-  f.FlushExecCtx();
-  track_counters.Finish(state);
+  s->Op(&op);
+  s->DestroyThen(MakeOnceClosure([s](grpc_error* error) { delete s; }));
   grpc_metadata_batch_destroy(&b);
   grpc_metadata_batch_destroy(&b_recv);
+  f.FlushExecCtx();
+  track_counters.Finish(state);
   grpc_slice_unref(incoming_data);
 }
 BENCHMARK(BM_TransportStreamRecv)->Range(0, 128 * 1024 * 1024);
index 263314d..edbff9c 100644 (file)
@@ -144,6 +144,99 @@ static void BM_EmptyCore(benchmark::State& state) {
 }
 BENCHMARK(BM_EmptyCore);
 
+// Helper for tests to shutdown correctly and tersely
+static void shutdown_and_destroy(grpc_completion_queue* cc) {
+  grpc_completion_queue_shutdown(cc);
+  grpc_completion_queue_destroy(cc);
+}
+
+static gpr_mu shutdown_mu, mu;
+static gpr_cv shutdown_cv, cv;
+
+// Tag completion queue iterate times
+class TagCallback : public grpc_experimental_completion_queue_functor {
+ public:
+  explicit TagCallback(int* iter) : iter_(iter) {
+    functor_run = &TagCallback::Run;
+  }
+  ~TagCallback() {}
+  static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+    gpr_mu_lock(&mu);
+    GPR_ASSERT(static_cast<bool>(ok));
+    *static_cast<TagCallback*>(cb)->iter_ += 1;
+    gpr_cv_signal(&cv);
+    gpr_mu_unlock(&mu);
+  };
+
+ private:
+  int* iter_;
+};
+
+// Check if completion queue is shut down
+class ShutdownCallback : public grpc_experimental_completion_queue_functor {
+ public:
+  explicit ShutdownCallback(bool* done) : done_(done) {
+    functor_run = &ShutdownCallback::Run;
+  }
+  ~ShutdownCallback() {}
+  static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+    gpr_mu_lock(&shutdown_mu);
+    *static_cast<ShutdownCallback*>(cb)->done_ = static_cast<bool>(ok);
+    gpr_cv_signal(&shutdown_cv);
+    gpr_mu_unlock(&shutdown_mu);
+  }
+
+ private:
+  bool* done_;
+};
+
+static void BM_Callback_CQ_Pass1Core(benchmark::State& state) {
+  TrackCounters track_counters;
+  int iteration = 0, current_iterations = 0;
+  TagCallback tag_cb(&iteration);
+  gpr_mu_init(&mu);
+  gpr_cv_init(&cv);
+  gpr_mu_init(&shutdown_mu);
+  gpr_cv_init(&shutdown_cv);
+  bool got_shutdown = false;
+  ShutdownCallback shutdown_cb(&got_shutdown);
+  grpc_completion_queue* cc =
+      grpc_completion_queue_create_for_callback(&shutdown_cb, nullptr);
+  while (state.KeepRunning()) {
+    grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+    grpc_core::ExecCtx exec_ctx;
+    grpc_cq_completion completion;
+    GPR_ASSERT(grpc_cq_begin_op(cc, &tag_cb));
+    grpc_cq_end_op(cc, &tag_cb, GRPC_ERROR_NONE, DoneWithCompletionOnStack,
+                   nullptr, &completion);
+  }
+  shutdown_and_destroy(cc);
+
+  gpr_mu_lock(&mu);
+  current_iterations = static_cast<int>(state.iterations());
+  while (current_iterations != iteration) {
+    // Wait for all the callbacks to complete.
+    gpr_cv_wait(&cv, &mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(&mu);
+
+  gpr_mu_lock(&shutdown_mu);
+  while (!got_shutdown) {
+    // Wait for the shutdown callback to complete.
+    gpr_cv_wait(&shutdown_cv, &shutdown_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(&shutdown_mu);
+
+  GPR_ASSERT(got_shutdown);
+  GPR_ASSERT(iteration == static_cast<int>(state.iterations()));
+  track_counters.Finish(state);
+  gpr_cv_destroy(&cv);
+  gpr_mu_destroy(&mu);
+  gpr_cv_destroy(&shutdown_cv);
+  gpr_mu_destroy(&shutdown_mu);
+}
+BENCHMARK(BM_Callback_CQ_Pass1Core);
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/microbenchmarks/callback_streaming_ping_pong.h b/test/cpp/microbenchmarks/callback_streaming_ping_pong.h
new file mode 100644 (file)
index 0000000..0d27e0e
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *
+ * Copyright 2019 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 TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H
+#define TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H
+
+#include <benchmark/benchmark.h>
+#include <sstream>
+#include "src/core/lib/profiling/timers.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/callback_test_service.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+
+namespace grpc {
+namespace testing {
+
+/*******************************************************************************
+ * BENCHMARKING KERNELS
+ */
+
+class BidiClient
+    : public grpc::experimental::ClientBidiReactor<EchoRequest, EchoResponse> {
+ public:
+  BidiClient(benchmark::State* state, EchoTestService::Stub* stub,
+             ClientContext* cli_ctx, EchoRequest* request,
+             EchoResponse* response)
+      : state_{state},
+        stub_{stub},
+        cli_ctx_{cli_ctx},
+        request_{request},
+        response_{response} {
+    msgs_size_ = state->range(0);
+    msgs_to_send_ = state->range(1);
+    StartNewRpc();
+  }
+
+  void OnReadDone(bool ok) override {
+    if (!ok) {
+      gpr_log(GPR_ERROR, "Client read failed");
+      return;
+    }
+    MaybeWrite();
+  }
+
+  void OnWriteDone(bool ok) override {
+    if (!ok) {
+      gpr_log(GPR_ERROR, "Client write failed");
+      return;
+    }
+    writes_complete_++;
+    StartRead(response_);
+  }
+
+  void OnDone(const Status& s) override {
+    GPR_ASSERT(s.ok());
+    GPR_ASSERT(writes_complete_ == msgs_to_send_);
+    if (state_->KeepRunning()) {
+      writes_complete_ = 0;
+      StartNewRpc();
+    } else {
+      std::unique_lock<std::mutex> l(mu);
+      done = true;
+      cv.notify_one();
+    }
+  }
+
+  void StartNewRpc() {
+    cli_ctx_->~ClientContext();
+    new (cli_ctx_) ClientContext();
+    cli_ctx_->AddMetadata(kServerMessageSize, grpc::to_string(msgs_size_));
+    stub_->experimental_async()->BidiStream(cli_ctx_, this);
+    MaybeWrite();
+    StartCall();
+  }
+
+  void Await() {
+    std::unique_lock<std::mutex> l(mu);
+    while (!done) {
+      cv.wait(l);
+    }
+  }
+
+ private:
+  void MaybeWrite() {
+    if (writes_complete_ < msgs_to_send_) {
+      StartWrite(request_);
+    } else {
+      StartWritesDone();
+    }
+  }
+
+  benchmark::State* state_;
+  EchoTestService::Stub* stub_;
+  ClientContext* cli_ctx_;
+  EchoRequest* request_;
+  EchoResponse* response_;
+  int writes_complete_{0};
+  int msgs_to_send_;
+  int msgs_size_;
+  std::mutex mu;
+  std::condition_variable cv;
+  bool done = false;
+};
+
+template <class Fixture, class ClientContextMutator, class ServerContextMutator>
+static void BM_CallbackBidiStreaming(benchmark::State& state) {
+  int message_size = state.range(0);
+  int max_ping_pongs = state.range(1);
+  CallbackStreamingTestService service;
+  std::unique_ptr<Fixture> fixture(new Fixture(&service));
+  std::unique_ptr<EchoTestService::Stub> stub_(
+      EchoTestService::NewStub(fixture->channel()));
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext cli_ctx;
+  if (message_size > 0) {
+    request.set_message(std::string(message_size, 'a'));
+  } else {
+    request.set_message("");
+  }
+  if (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+    BidiClient test{&state, stub_.get(), &cli_ctx, &request, &response};
+    test.Await();
+  }
+  fixture->Finish(state);
+  fixture.reset();
+  state.SetBytesProcessed(2 * message_size * max_ping_pongs *
+                          state.iterations());
+}
+
+}  // namespace testing
+}  // namespace grpc
+#endif  // TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H
diff --git a/test/cpp/microbenchmarks/callback_test_service.cc b/test/cpp/microbenchmarks/callback_test_service.cc
new file mode 100644 (file)
index 0000000..321a5b3
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2019 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/microbenchmarks/callback_test_service.h"
+
+namespace grpc {
+namespace testing {
+namespace {
+
+grpc::string ToString(const grpc::string_ref& r) {
+  return grpc::string(r.data(), r.size());
+}
+
+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;
+  }
+
+  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);
+}
+}  // namespace
+
+void CallbackStreamingTestService::Echo(
+    ServerContext* context, const EchoRequest* request, EchoResponse* response,
+    experimental::ServerCallbackRpcController* controller) {
+  int response_msgs_size = GetIntValueFromMetadata(
+      kServerMessageSize, context->client_metadata(), 0);
+  if (response_msgs_size > 0) {
+    response->set_message(std::string(response_msgs_size, 'a'));
+  } else {
+    response->set_message("");
+  }
+  controller->Finish(Status::OK);
+}
+
+experimental::ServerBidiReactor<EchoRequest, EchoResponse>*
+CallbackStreamingTestService::BidiStream() {
+  class Reactor
+      : public experimental::ServerBidiReactor<EchoRequest, EchoResponse> {
+   public:
+    Reactor() {}
+    void OnStarted(ServerContext* context) override {
+      ctx_ = context;
+      message_size_ = GetIntValueFromMetadata(kServerMessageSize,
+                                              context->client_metadata(), 0);
+      StartRead(&request_);
+    }
+    void OnDone() override {
+      GPR_ASSERT(finished_);
+      delete this;
+    }
+    void OnCancel() override {}
+    void OnReadDone(bool ok) override {
+      if (!ok) {
+        // Stream is over
+        Finish(::grpc::Status::OK);
+        finished_ = true;
+        return;
+      }
+      if (message_size_ > 0) {
+        response_.set_message(std::string(message_size_, 'a'));
+      } else {
+        response_.set_message("");
+      }
+      StartWrite(&response_);
+    }
+    void OnWriteDone(bool ok) override {
+      if (!ok) {
+        gpr_log(GPR_ERROR, "Server write failed");
+        return;
+      }
+      StartRead(&request_);
+    }
+
+   private:
+    ServerContext* ctx_;
+    EchoRequest request_;
+    EchoResponse response_;
+    int message_size_;
+    bool finished_{false};
+  };
+
+  return new Reactor;
+}
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/microbenchmarks/callback_test_service.h b/test/cpp/microbenchmarks/callback_test_service.h
new file mode 100644 (file)
index 0000000..9718859
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2019 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 TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H
+#define TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H
+
+#include <benchmark/benchmark.h>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+namespace grpc {
+namespace testing {
+
+const char* const kServerMessageSize = "server_message_size";
+
+class CallbackStreamingTestService
+    : public EchoTestService::ExperimentalCallbackService {
+ public:
+  CallbackStreamingTestService() {}
+  void Echo(ServerContext* context, const EchoRequest* request,
+            EchoResponse* response,
+            experimental::ServerCallbackRpcController* controller) override;
+
+  experimental::ServerBidiReactor<EchoRequest, EchoResponse>* BidiStream()
+      override;
+};
+}  // namespace testing
+}  // namespace grpc
+#endif  // TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H
diff --git a/test/cpp/microbenchmarks/callback_unary_ping_pong.h b/test/cpp/microbenchmarks/callback_unary_ping_pong.h
new file mode 100644 (file)
index 0000000..359b91e
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2019 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.
+ *
+ */
+
+/* Benchmark gRPC end2end in various configurations */
+
+#ifndef TEST_CPP_MICROBENCHMARKS_CALLBACK_UNARY_PING_PONG_H
+#define TEST_CPP_MICROBENCHMARKS_CALLBACK_UNARY_PING_PONG_H
+
+#include <benchmark/benchmark.h>
+#include <sstream>
+#include "src/core/lib/profiling/timers.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/callback_test_service.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+
+namespace grpc {
+namespace testing {
+
+/*******************************************************************************
+ * BENCHMARKING KERNELS
+ */
+
+void SendCallbackUnaryPingPong(benchmark::State* state, ClientContext* cli_ctx,
+                               EchoRequest* request, EchoResponse* response,
+                               EchoTestService::Stub* stub_, bool* done,
+                               std::mutex* mu, std::condition_variable* cv) {
+  int response_msgs_size = state->range(1);
+  cli_ctx->AddMetadata(kServerMessageSize, grpc::to_string(response_msgs_size));
+  stub_->experimental_async()->Echo(
+      cli_ctx, request, response,
+      [state, cli_ctx, request, response, stub_, done, mu, cv](Status s) {
+        GPR_ASSERT(s.ok());
+        if (state->KeepRunning()) {
+          cli_ctx->~ClientContext();
+          new (cli_ctx) ClientContext();
+          SendCallbackUnaryPingPong(state, cli_ctx, request, response, stub_,
+                                    done, mu, cv);
+        } else {
+          std::lock_guard<std::mutex> l(*mu);
+          *done = true;
+          cv->notify_one();
+        }
+      });
+};
+
+template <class Fixture, class ClientContextMutator, class ServerContextMutator>
+static void BM_CallbackUnaryPingPong(benchmark::State& state) {
+  int request_msgs_size = state.range(0);
+  int response_msgs_size = state.range(1);
+  CallbackStreamingTestService service;
+  std::unique_ptr<Fixture> fixture(new Fixture(&service));
+  std::unique_ptr<EchoTestService::Stub> stub_(
+      EchoTestService::NewStub(fixture->channel()));
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext cli_ctx;
+
+  if (request_msgs_size > 0) {
+    request.set_message(std::string(request_msgs_size, 'a'));
+  } else {
+    request.set_message("");
+  }
+
+  std::mutex mu;
+  std::condition_variable cv;
+  bool done = false;
+  if (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+    SendCallbackUnaryPingPong(&state, &cli_ctx, &request, &response,
+                              stub_.get(), &done, &mu, &cv);
+  }
+  std::unique_lock<std::mutex> l(mu);
+  while (!done) {
+    cv.wait(l);
+  }
+  fixture->Finish(state);
+  fixture.reset();
+  state.SetBytesProcessed(request_msgs_size * state.iterations() +
+                          response_msgs_size * state.iterations());
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // TEST_CPP_MICROBENCHMARKS_FULLSTACK_UNARY_PING_PONG_H
index bad24cf..059dc4f 100644 (file)
@@ -479,7 +479,7 @@ class ClientRpcContextStreamingPingPongImpl : public ClientRpcContext {
     next_state_ = State::STREAM_IDLE;
     stream_->StartCall(ClientRpcContext::tag(this));
     if (coalesce_) {
-      // When the intial metadata is corked, the tag will not come back and we
+      // When the initial metadata is corked, the tag will not come back and we
       // need to manually drive the state machine.
       RunNextState(true, nullptr);
     }
index dcfa2db..d22264d 100644 (file)
@@ -43,13 +43,14 @@ namespace testing {
  * Maintains context info per RPC
  */
 struct CallbackClientRpcContext {
-  CallbackClientRpcContext(BenchmarkService::Stub* stub) : stub_(stub) {}
+  CallbackClientRpcContext(BenchmarkService::Stub* stub)
+      : alarm_(nullptr), stub_(stub) {}
 
   ~CallbackClientRpcContext() {}
 
   SimpleResponse response_;
   ClientContext context_;
-  Alarm alarm_;
+  std::unique_ptr<Alarm> alarm_;
   BenchmarkService::Stub* stub_;
 };
 
@@ -169,7 +170,10 @@ class CallbackUnaryClient final : public CallbackClient {
       gpr_timespec next_issue_time = NextRPCIssueTime();
       // Start an alarm callback to run the internal callback after
       // next_issue_time
-      ctx_[vector_idx]->alarm_.experimental().Set(
+      if (ctx_[vector_idx]->alarm_ == nullptr) {
+        ctx_[vector_idx]->alarm_.reset(new Alarm);
+      }
+      ctx_[vector_idx]->alarm_->experimental().Set(
           next_issue_time, [this, t, vector_idx](bool ok) {
             IssueUnaryCallbackRpc(t, vector_idx);
           });
@@ -289,7 +293,7 @@ class CallbackStreamingPingPongReactor final
       gpr_timespec next_issue_time = client_->NextRPCIssueTime();
       // Start an alarm callback to run the internal callback after
       // next_issue_time
-      ctx_->alarm_.experimental().Set(next_issue_time, [this](bool ok) {
+      ctx_->alarm_->experimental().Set(next_issue_time, [this](bool ok) {
         write_time_ = UsageTimer::Now();
         StartWrite(client_->request());
       });
@@ -313,8 +317,11 @@ class CallbackStreamingPingPongReactor final
       gpr_timespec next_issue_time = client_->NextRPCIssueTime();
       // Start an alarm callback to run the internal callback after
       // next_issue_time
-      ctx_->alarm_.experimental().Set(next_issue_time,
-                                      [this](bool ok) { StartNewRpc(); });
+      if (ctx_->alarm_ == nullptr) {
+        ctx_->alarm_.reset(new Alarm);
+      }
+      ctx_->alarm_->experimental().Set(next_issue_time,
+                                       [this](bool ok) { StartNewRpc(); });
     } else {
       StartNewRpc();
     }
index bb1ca86..d112611 100644 (file)
@@ -75,6 +75,7 @@ grpc_cc_library(
         "test_credentials_provider.h",
     ],
     external_deps = [
+        "gflags",
         "protobuf",
     ],
     deps = [
index 3f27909..65144a1 100644 (file)
 #include <grpcpp/support/status.h>
 #include <grpcpp/support/string_ref.h>
 
-namespace grpc {
+namespace grpc_impl {
 
 class ClientContext;
+}  // namespace grpc_impl
+namespace grpc {
 
 namespace testing {
 
@@ -85,7 +87,7 @@ class CliCall final {
 
  private:
   std::unique_ptr<grpc::GenericStub> stub_;
-  grpc::ClientContext ctx_;
+  grpc_impl::ClientContext ctx_;
   std::unique_ptr<grpc::GenericClientAsyncReaderWriter> call_;
   grpc::CompletionQueue cq_;
   gpr_mu write_mu_;
index 455f94e..fd79637 100644 (file)
 
 #include "test/cpp/util/test_credentials_provider.h"
 
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+
 #include <mutex>
 #include <unordered_map>
 
+#include <gflags/gflags.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpcpp/security/server_credentials.h>
 
 #include "test/core/end2end/data/ssl_test_data.h"
 
+DEFINE_string(tls_cert_file, "", "The TLS cert file used when --use_tls=true");
+DEFINE_string(tls_key_file, "", "The TLS key file used when --use_tls=true");
+
 namespace grpc {
 namespace testing {
 namespace {
 
+grpc::string ReadFile(const grpc::string& src_path) {
+  std::ifstream src;
+  src.open(src_path, std::ifstream::in | std::ifstream::binary);
+
+  grpc::string contents;
+  src.seekg(0, std::ios::end);
+  contents.reserve(src.tellg());
+  src.seekg(0, std::ios::beg);
+  contents.assign((std::istreambuf_iterator<char>(src)),
+                  (std::istreambuf_iterator<char>()));
+  return contents;
+}
+
 class DefaultCredentialsProvider : public CredentialsProvider {
  public:
+  DefaultCredentialsProvider() {
+    if (!FLAGS_tls_key_file.empty()) {
+      custom_server_key_ = ReadFile(FLAGS_tls_key_file);
+    }
+    if (!FLAGS_tls_cert_file.empty()) {
+      custom_server_cert_ = ReadFile(FLAGS_tls_cert_file);
+    }
+  }
   ~DefaultCredentialsProvider() override {}
 
   void AddSecureType(
@@ -87,11 +116,17 @@ class DefaultCredentialsProvider : public CredentialsProvider {
       grpc::experimental::AltsServerCredentialsOptions alts_opts;
       return grpc::experimental::AltsServerCredentials(alts_opts);
     } else if (type == grpc::testing::kTlsCredentialsType) {
-      SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
-                                                          test_server1_cert};
       SslServerCredentialsOptions ssl_opts;
       ssl_opts.pem_root_certs = "";
-      ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+      if (!custom_server_key_.empty() && !custom_server_cert_.empty()) {
+        SslServerCredentialsOptions::PemKeyCertPair pkcp = {
+            custom_server_key_, custom_server_cert_};
+        ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+      } else {
+        SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
+                                                            test_server1_cert};
+        ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+      }
       return SslServerCredentials(ssl_opts);
     } else {
       std::unique_lock<std::mutex> lock(mu_);
@@ -121,6 +156,8 @@ class DefaultCredentialsProvider : public CredentialsProvider {
   std::vector<grpc::string> added_secure_type_names_;
   std::vector<std::unique_ptr<CredentialTypeProvider>>
       added_secure_type_providers_;
+  grpc::string custom_server_key_;
+  grpc::string custom_server_cert_;
 };
 
 CredentialsProvider* g_provider = nullptr;
index a71c85f..95ae7c5 100644 (file)
@@ -1,5 +1,5 @@
 cc_library(
-    name = "z",
+    name = "zlib",
     srcs = [
         "adler32.c",
         "compress.c",
diff --git a/tools/bazel b/tools/bazel
new file mode 100755 (executable)
index 0000000..bacfead
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Copyright 2019 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.
+
+
+# Keeping up with Bazel's breaking changes is currently difficult.
+# This script wraps calling bazel by downloading the currently
+# supported version, and then calling it. This way, we can make sure
+# that running bazel will always get meaningful results, at least
+# until Bazel 1.0 is released.
+# NOTE: This script relies on bazel's feature where //tools/bazel
+# script can be used to hijack "bazel" invocations in given workspace.
+
+set -e
+
+# First of all, if DISABLE_BAZEL_WRAPPER is set, just use BAZEL_REAL as set by
+# https://github.com/bazelbuild/bazel/blob/master/scripts/packages/bazel.sh
+# that originally invoked this script.
+if [ "${BAZEL_REAL}" != "" ] && [ "${DISABLE_BAZEL_WRAPPER}" != "" ]
+then
+  exec -a "$0" "${BAZEL_REAL}" "$@"
+fi
+
+VERSION=0.24.1
+
+echo "INFO: Running bazel wrapper (see //tools/bazel for details), bazel version $VERSION will be used instead of system-wide bazel installation."
+
+BASEURL=https://github.com/bazelbuild/bazel/releases/download/
+pushd "$(dirname "$0")" >/dev/null
+TOOLDIR=$(pwd)
+
+case $(uname -sm) in
+  "Linux x86_64")
+    suffix=linux-x86_64
+    ;;
+  "Darwin x86_64")
+    suffix=darwin-x86_64
+    ;;
+  *)
+    echo "Unsupported architecture: $(uname -sm)"
+    exit 1
+    ;;
+esac
+
+filename="bazel-$VERSION-$suffix"
+
+if [ ! -x "$filename" ] ; then
+  curl -L "$BASEURL/$VERSION/$filename" > "$filename"
+  chmod a+x "$filename"
+fi
+
+popd >/dev/null
+exec "$TOOLDIR/$filename" "$@"
index 5545e87..b534d8d 100755 (executable)
@@ -376,6 +376,8 @@ print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
 print >> H
 print >> H, '#include <grpc/support/port_platform.h>'
 print >> H
+print >> H, '#include <cstdint>'
+print >> H
 print >> H, '#include "src/core/lib/transport/metadata.h"'
 print >> H
 print >> C, '#include <grpc/support/port_platform.h>'
@@ -433,8 +435,8 @@ for i, elem in enumerate(all_strs):
 print >> C, '};'
 print >> C
 print >> H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\'
-print >> H, ('  ((int)((static_slice).refcount - '
-             'grpc_static_metadata_refcounts))')
+print >> H, ('  (static_cast<intptr_t>(((static_slice).refcount - '
+             'grpc_static_metadata_refcounts)))')
 print >> H
 
 print >> D, '# hpack fuzzing dictionary'
@@ -445,14 +447,15 @@ for i, elem in enumerate(all_elems):
                                  [len(elem[1])] + [ord(c) for c in elem[1]]))
 
 print >> H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems)
-print >> H, ('extern grpc_mdelem_data '
+print >> H, ('extern grpc_core::StaticMetadata '
              'grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];')
 print >> H, ('extern uintptr_t '
              'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];')
 for i, elem in enumerate(all_elems):
     print >> H, '/* "%s": "%s" */' % elem
-    print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], '
-                 'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i)
+    print >> H, (
+        '#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d].data(), '
+        'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i)
 print >> H
 
 print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] '
@@ -537,18 +540,19 @@ print >> C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join(
     '%d' % i for i in idxs)
 print >> C
 
-print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);'
-print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {'
+print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);'
+print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {'
 print >> C, '  if (a == -1 || b == -1) return GRPC_MDNULL;'
-print >> C, '  uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs)
+print >> C, '  uint32_t k = static_cast<uint32_t>(a * %d + b);' % len(all_strs)
 print >> C, '  uint32_t h = elems_phash(k);'
-print >> C, '  return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;'
+print >> C, '  return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]].data(), GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;'
 print >> C, '}'
 print >> C
 
-print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
+print >> C, 'grpc_core::StaticMetadata grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
 for a, b in all_elems:
-    print >> C, '{%s,%s},' % (slice_def(str_idx(a)), slice_def(str_idx(b)))
+    print >> C, 'grpc_core::StaticMetadata(%s,%s),' % (slice_def(str_idx(a)),
+                                                       slice_def(str_idx(b)))
 print >> C, '};'
 
 print >> H, 'typedef enum {'
@@ -566,7 +570,7 @@ print >> H, '  } named;'
 print >> H, '} grpc_metadata_batch_callouts;'
 print >> H
 print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
-print >> H, '  (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
+print >> H, '  (GRPC_IS_STATIC_METADATA_STRING((slice)) ? static_cast<grpc_metadata_batch_callouts_index>(GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, static_cast<intptr_t>(GRPC_BATCH_CALLOUTS_COUNT))) : GRPC_BATCH_CALLOUTS_COUNT)'
 print >> H
 
 print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (
@@ -577,7 +581,7 @@ print >> C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems)
 print >> C, '};'
 print >> C
 
-print >> H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))'
+print >> H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]].data(), GRPC_MDELEM_STORAGE_STATIC))'
 print >> H
 
 print >> H, 'extern const uint8_t grpc_static_accept_stream_encoding_metadata[%d];' % (
@@ -588,7 +592,7 @@ print >> C, '0,%s' % ','.join(
     '%d' % md_idx(elem) for elem in stream_compression_elems)
 print >> C, '};'
 
-print >> H, '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_stream_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))'
+print >> H, '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_stream_encoding_metadata[(algs)]].data(), GRPC_MDELEM_STORAGE_STATIC))'
 
 print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'
 
index bb71101..69c53da 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.21.3'
+VERSION = '1.22.0'
index e7e4ba3..3eef24f 100644 (file)
 # limitations under the License.
 
 # AUTO-GENERATED BY make_grpcio_tools.py!
-CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_padding_optimizer.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/util/delimited_message_util.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_table_driven.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/io_win32.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/implicit_weak_message.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/generated_message_table_driven_lite.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arena.cc']
+CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_padding_optimizer.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/util/delimited_message_util.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_table_driven.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/parse_context.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/io_win32.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/implicit_weak_message.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/generated_message_table_driven_lite.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arena.cc', 'google/protobuf/any_lite.cc']
 PROTO_FILES=['google/protobuf/wrappers.proto', 'google/protobuf/type.proto', 'google/protobuf/timestamp.proto', 'google/protobuf/struct.proto', 'google/protobuf/source_context.proto', 'google/protobuf/field_mask.proto', 'google/protobuf/empty.proto', 'google/protobuf/duration.proto', 'google/protobuf/descriptor.proto', 'google/protobuf/compiler/plugin.proto', 'google/protobuf/api.proto', 'google/protobuf/any.proto']
 
 CC_INCLUDE='third_party/protobuf/src'
 PROTO_INCLUDE='third_party/protobuf/src'
 
-PROTOBUF_SUBMODULE_VERSION="582743bf40c5d3639a70f98f183914a2c0cd0680"
+PROTOBUF_SUBMODULE_VERSION="09745575a923640154bcf307fba8aedff47f240a"
index b53ffc2..0812b86 100644 (file)
@@ -22,14 +22,14 @@ RUN yum install -y tar which
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
-# Install Ruby 2.2
+# Install Ruby 2.3
 # Running the installation twice to work around docker issue when using overlay.
 # https://github.com/docker/docker/issues/10180
-RUN (/bin/bash -l -c "rvm install ruby-2.2.10") || (/bin/bash -l -c "rvm install ruby-2.2.10")
-RUN /bin/bash -l -c "rvm use --default ruby-2.2.10"
+RUN (/bin/bash -l -c "rvm install ruby-2.3.8") || (/bin/bash -l -c "rvm install ruby-2.3.8")
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.2.10' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
index 72235bf..fc4eabb 100644 (file)
@@ -20,12 +20,12 @@ RUN yum update && yum install -y curl tar which
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
-# Install Ruby 2.2
-RUN /bin/bash -l -c "rvm install ruby-2.2.10"
-RUN /bin/bash -l -c "rvm use --default ruby-2.2.10"
+# Install Ruby 2.3
+RUN /bin/bash -l -c "rvm install ruby-2.3.8"
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.2.10' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
index 3d688a8..73a4bd7 100644 (file)
@@ -21,14 +21,14 @@ RUN yum clean all && yum update -y && yum distro-sync -y && yum install -y opens
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
-# Install Ruby 2.2
+# Install Ruby 2.3
 # Running the installation twice to work around docker issue when using overlay.
 # https://github.com/docker/docker/issues/10180
-RUN (/bin/bash -l -c "rvm install ruby-2.2.10") || (/bin/bash -l -c "rvm install ruby-2.2.10")
-RUN /bin/bash -l -c "rvm use --default ruby-2.2.10"
+RUN (/bin/bash -l -c "rvm install ruby-2.3.8") || (/bin/bash -l -c "rvm install ruby-2.3.8")
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.2.10' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
index 8044adf..43c0ae5 100644 (file)
@@ -26,12 +26,12 @@ RUN yum clean all && yum update -y && yum distro-sync -y && yum install -y opens
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
-# Install Ruby 2.2
-RUN /bin/bash -l -c "rvm install ruby-2.2.10"
-RUN /bin/bash -l -c "rvm use --default ruby-2.2.10"
+# Install Ruby 2.3
+RUN /bin/bash -l -c "rvm install ruby-2.3.8"
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.2.10' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
index 848c5be..e077f68 100644 (file)
 
 FROM fedora:22
 
-RUN yum clean all && yum update -y && yum install -y ruby findutils
+# Make yum work properly under docker when using overlay storage driver.
+# https://bugzilla.redhat.com/show_bug.cgi?id=1213602#c9
+# https://github.com/docker/docker/issues/10180
+RUN yum install -y yum-plugin-ovl
 
-RUN gem install bundler
+# distro-sync and install openssl, per https://github.com/fedora-cloud/docker-brew-fedora/issues/19
+RUN yum clean all && yum update -y && yum distro-sync -y && yum install -y openssl gnupg which findutils tar procps
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+RUN curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.3
+RUN /bin/bash -l -c "rvm install ruby-2.3.8"
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
+RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.3.8' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
+
+RUN mkdir /var/local/jenkins
+
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
index 47dd577..f586ae3 100644 (file)
 
 FROM fedora:23
 
-RUN yum clean all && yum update -y && yum install -y ruby findutils
+# Make yum work properly under docker when using overlay storage driver.
+# https://bugzilla.redhat.com/show_bug.cgi?id=1213602#c9
+# https://github.com/docker/docker/issues/10180
+RUN yum install -y yum-plugin-ovl
 
-RUN gem install bundler
+# distro-sync and install openssl, per https://github.com/fedora-cloud/docker-brew-fedora/issues/19
+RUN yum clean all && yum update -y && yum distro-sync -y && yum install -y openssl gnupg which findutils tar procps
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+RUN curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.3
+RUN /bin/bash -l -c "rvm install ruby-2.3.8"
+RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
+RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.3.8' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
+
+RUN mkdir /var/local/jenkins
+
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
diff --git a/tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_2/Dockerfile b/tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_2/Dockerfile
deleted file mode 100644 (file)
index 337fc3b..0000000
+++ /dev/null
@@ -1,40 +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.
-
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  curl \
-  gcc && apt-get clean
-
-#==================
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.2
-RUN /bin/bash -l -c "rvm install ruby-2.2.10"
-RUN /bin/bash -l -c "rvm use --default ruby-2.2.10"
-RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.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.2.10' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
index fb83a5c..e2c4065 100644 (file)
 
 # Docker file for building gRPC Raspbian binaries
 
+# TODO(https://github.com/grpc/grpc/issues/19199): Move off of this image.
 FROM quay.io/grpc/raspbian_armv6
 
 # Place any extra build instructions between these commands
 # Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv6)
 # for build steps because running them under QEMU is very slow
 # (https://github.com/kpayson64/armv7hf-debian-qemu)
-# RUN [ "cross-build-start" ]
-# RUN [ "cross-build-end" ]
+RUN [ "cross-build-start" ]
+RUN find /usr/local/bin -regex '.*python[0-9]+\.[0-9]+' | xargs -n1 -i{} bash -c "{} -m pip install --upgrade wheel setuptools"
+RUN [ "cross-build-end" ]
index 0b68df5..735c2e8 100644 (file)
 
 # Docker file for building gRPC Raspbian binaries
 
+# TODO(https://github.com/grpc/grpc/issues/19199): Move off of this base image.
 FROM quay.io/grpc/raspbian_armv7
 
 # Place any extra build instructions between these commands
 # Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv7)
 # for build steps because running them under QEMU is very slow
 # (https://github.com/kpayson64/armv7hf-debian-qemu)
-# RUN [ "cross-build-start" ]
-# RUN [ "cross-build-end" ]
+RUN [ "cross-build-start" ]
+RUN find /usr/local/bin -regex '.*python[0-9]+\.[0-9]+' | xargs -n1 -i{} bash -c "{} -m pip install --upgrade wheel setuptools"
+RUN [ "cross-build-end" ]
index 2a3e6f3..acb2a0a 100644 (file)
@@ -37,7 +37,4 @@ then
   ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet
 fi
 
-./build/get-grpc.sh
-
-cd testassets/InteropTestsWebsite
-dotnet build --configuration Debug
+dotnet build --configuration Debug Grpc.DotNet.sln
index 979c14d..b7664b3 100644 (file)
 FROM debian:jessie
 
 
-# Install JDK 8
-#
-RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
-  echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
-  echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
-  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && \
-  apt-get update && apt-get -y install oracle-java8-installer && \
-  apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
-
-ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-ENV PATH $PATH:$JAVA_HOME/bin
-
-
+RUN echo "deb http://archive.debian.org/debian/ jessie-backports main contrib non-free" > /etc/apt/sources.list.d/jessie-backports.list && \
+    echo 'Acquire::Check-Valid-Until no;' > /etc/apt/apt.conf.d/99no-check-valid-until && \
+    apt-get update && \
+    apt-get install -y --no-install-recommends -t jessie-backports openjdk-8-jdk-headless && \
+    apt-get clean
 
 # Define the default command.
 CMD ["bash"]
index 8e11546..77d3228 100644 (file)
@@ -41,4 +41,4 @@ java.util.logging.ConsoleHandler.level = ALL
 .level = FINE
 io.grpc.netty.NettyClientHandler = ALL
 io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
-
+  
diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
deleted file mode 100644 (file)
index 979c14d..0000000
+++ /dev/null
@@ -1,34 +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.
-
-FROM debian:jessie
-
-
-# Install JDK 8
-#
-RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
-  echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
-  echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
-  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && \
-  apt-get update && apt-get -y install oracle-java8-installer && \
-  apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
-
-ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-ENV PATH $PATH:$JAVA_HOME/bin
-
-
-
-# Define the default command.
-CMD ["bash"]
-
diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh
deleted file mode 100644 (file)
index 77d3228..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-# 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.
-#
-# Builds Java interop server and client in a base image.
-set -e
-
-cp -r /var/local/jenkins/grpc-java /tmp/grpc-java
-
-# copy service account keys if available
-cp -r /var/local/jenkins/service_account $HOME || true
-
-pushd /tmp/grpc-java
-./gradlew :grpc-interop-testing:installDist -PskipCodegen=true
-
-mkdir -p /var/local/git/grpc-java/
-cp -r --parents -t /var/local/git/grpc-java/ \
-    interop-testing/build/install/ \
-    run-test-client.sh \
-    run-test-server.sh
-
-popd
-rm -r /tmp/grpc-java
-rm -r "$HOME/.gradle"
-
-# enable extra java logging
-mkdir -p /var/local/grpc_java_logging
-echo "handlers = java.util.logging.ConsoleHandler
-java.util.logging.ConsoleHandler.level = ALL
-.level = FINE
-io.grpc.netty.NettyClientHandler = ALL
-io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
-  
index 2536fe2..df7a7a2 100644 (file)
@@ -51,10 +51,16 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
 #========================
 # Bazel installation
 
+# Must be in sync with tools/bazel
+ENV BAZEL_VERSION 0.24.1
+
+# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper.
+ENV DISABLE_BAZEL_WRAPPER 1
+
 RUN apt-get update && apt-get install -y wget && apt-get clean
-RUN wget https://github.com/bazelbuild/bazel/releases/download/0.23.2/bazel-0.23.2-installer-linux-x86_64.sh && \
-  bash ./bazel-0.23.2-installer-linux-x86_64.sh && \
-  rm bazel-0.23.2-installer-linux-x86_64.sh
+RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && \
+  bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && \
+  rm bazel-$BAZEL_VERSION-installer-linux-x86_64.sh
 
 
 RUN mkdir -p /var/local/jenkins
diff --git a/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile b/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile
new file mode 100644 (file)
index 0000000..d5ecbc7
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright 2019 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.
+
+FROM debian:stretch
+  
+# 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
+
+# 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
+
+# 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 install -y jq zlib1g-dev libssl-dev
+
+COPY get_cpython.sh /tmp
+RUN apt-get install -y jq build-essential libffi-dev && \
+  chmod +x /tmp/get_cpython.sh && \
+  /tmp/get_cpython.sh && \
+  rm /tmp/get_cpython.sh
+
+RUN python3.8 -m ensurepip && \
+    python3.8 -m pip install coverage
diff --git a/tools/dockerfile/test/python_stretch_3.8_x64/get_cpython.sh b/tools/dockerfile/test/python_stretch_3.8_x64/get_cpython.sh
new file mode 100644 (file)
index 0000000..e051e97
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright 2019 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.
+
+VERSION_REGEX="v3.8.*"
+REPO="python/cpython"
+
+LATEST=$(curl -s https://api.github.com/repos/$REPO/tags | \
+          jq -r '.[] | select(.name|test("'$VERSION_REGEX'")) | .name' \
+          | sort | tail -n1)
+
+wget https://github.com/$REPO/archive/$LATEST.tar.gz
+tar xzvf *.tar.gz
+( cd cpython*
+  ./configure
+  make install
+)
index 765bd72..9a080d0 100644 (file)
@@ -97,10 +97,16 @@ ENV CLANG_TIDY=clang-tidy
 #========================
 # Bazel installation
 
+# Must be in sync with tools/bazel
+ENV BAZEL_VERSION 0.24.1
+
+# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper.
+ENV DISABLE_BAZEL_WRAPPER 1
+
 RUN apt-get update && apt-get install -y wget && apt-get clean
-RUN wget https://github.com/bazelbuild/bazel/releases/download/0.23.2/bazel-0.23.2-installer-linux-x86_64.sh && \
-  bash ./bazel-0.23.2-installer-linux-x86_64.sh && \
-  rm bazel-0.23.2-installer-linux-x86_64.sh
+RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && \
+  bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && \
+  rm bazel-$BAZEL_VERSION-installer-linux-x86_64.sh
 
 
 # Define the default command.
index 15f82e9..f43cff4 100644 (file)
@@ -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.21.3
+PROJECT_NUMBER         = 1.22.0
 
 # 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
@@ -956,6 +956,7 @@ include/grpcpp/impl/codegen/callback_common.h \
 include/grpcpp/impl/codegen/channel_interface.h \
 include/grpcpp/impl/codegen/client_callback.h \
 include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_context_impl.h \
 include/grpcpp/impl/codegen/client_interceptor.h \
 include/grpcpp/impl/codegen/client_unary_call.h \
 include/grpcpp/impl/codegen/completion_queue.h \
@@ -982,6 +983,7 @@ 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_context_impl.h \
 include/grpcpp/impl/codegen/server_interceptor.h \
 include/grpcpp/impl/codegen/server_interface.h \
 include/grpcpp/impl/codegen/service_type.h \
@@ -1040,7 +1042,8 @@ include/grpcpp/support/status_code_enum.h \
 include/grpcpp/support/string_ref.h \
 include/grpcpp/support/stub_options.h \
 include/grpcpp/support/sync_stream.h \
-include/grpcpp/support/time.h
+include/grpcpp/support/time.h \
+include/grpcpp/support/validate_service_config.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
index 6361441..29c7901 100644 (file)
@@ -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.21.3
+PROJECT_NUMBER         = 1.22.0
 
 # 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
@@ -957,6 +957,7 @@ include/grpcpp/impl/codegen/callback_common.h \
 include/grpcpp/impl/codegen/channel_interface.h \
 include/grpcpp/impl/codegen/client_callback.h \
 include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_context_impl.h \
 include/grpcpp/impl/codegen/client_interceptor.h \
 include/grpcpp/impl/codegen/client_unary_call.h \
 include/grpcpp/impl/codegen/completion_queue.h \
@@ -984,6 +985,7 @@ 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_context_impl.h \
 include/grpcpp/impl/codegen/server_interceptor.h \
 include/grpcpp/impl/codegen/server_interface.h \
 include/grpcpp/impl/codegen/service_type.h \
@@ -1043,6 +1045,7 @@ include/grpcpp/support/string_ref.h \
 include/grpcpp/support/stub_options.h \
 include/grpcpp/support/sync_stream.h \
 include/grpcpp/support/time.h \
+include/grpcpp/support/validate_service_config.h \
 src/core/ext/filters/client_channel/health/health.pb.c \
 src/core/ext/filters/client_channel/health/health.pb.h \
 src/core/ext/transport/inproc/inproc_transport.h \
@@ -1188,6 +1191,7 @@ src/core/lib/slice/percent_encoding.h \
 src/core/lib/slice/slice_hash_table.h \
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/slice/slice_utils.h \
 src/core/lib/slice/slice_weak_hash_table.h \
 src/core/lib/surface/api_trace.h \
 src/core/lib/surface/call.h \
@@ -1244,12 +1248,15 @@ src/cpp/common/secure_auth_context.cc \
 src/cpp/common/secure_auth_context.h \
 src/cpp/common/secure_channel_arguments.cc \
 src/cpp/common/secure_create_auth_context.cc \
+src/cpp/common/validate_service_config.cc \
 src/cpp/common/version_cc.cc \
 src/cpp/server/async_generic_service.cc \
 src/cpp/server/channel_argument_option.cc \
 src/cpp/server/create_default_thread_pool.cc \
 src/cpp/server/dynamic_thread_pool.cc \
 src/cpp/server/dynamic_thread_pool.h \
+src/cpp/server/external_connection_acceptor_impl.cc \
+src/cpp/server/external_connection_acceptor_impl.h \
 src/cpp/server/health/default_health_check_service.cc \
 src/cpp/server/health/default_health_check_service.h \
 src/cpp/server/health/health_check_service.cc \
index b34c773..7768bca 100644 (file)
@@ -974,6 +974,7 @@ src/core/ext/filters/client_channel/service_config.cc \
 src/core/ext/filters/client_channel/service_config.h \
 src/core/ext/filters/client_channel/subchannel.cc \
 src/core/ext/filters/client_channel/subchannel.h \
+src/core/ext/filters/client_channel/subchannel_interface.h \
 src/core/ext/filters/client_channel/subchannel_pool_interface.cc \
 src/core/ext/filters/client_channel/subchannel_pool_interface.h \
 src/core/ext/filters/deadline/deadline_filter.cc \
@@ -1449,6 +1450,7 @@ src/core/lib/slice/slice_intern.cc \
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.cc \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/slice/slice_utils.h \
 src/core/lib/slice/slice_weak_hash_table.h \
 src/core/lib/surface/README.md \
 src/core/lib/surface/api_trace.cc \
index e462a83..03105d9 100644 (file)
@@ -30,7 +30,6 @@ git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
 git clone --recursive https://github.com/grpc/grpc-dart ./../grpc-dart
 git clone --recursive https://github.com/grpc/grpc-dotnet ./../grpc-dotnet
 
-# Download json file.
+# Grab the service account key to run interop tests against prod backends.
 mkdir ~/service_account
-gsutil cp gs://grpc-testing-secrets/interop/service_account/GrpcTesting-726eb1347f15.json ~/service_account
-export GOOGLE_APPLICATION_CREDENTIALS=~/service_account/GrpcTesting-726eb1347f15.json
+cp "${KOKORO_KEYSTORE_DIR}/73836_interop_to_prod_tests_service_account_key" ~/service_account/grpc-testing-ebe7c1ac7381.json || true
index ff5593e..bd8c300 100644 (file)
 ulimit -n 32768
 ulimit -c unlimited
 
-# Performance PR testing needs GH API key and PR metadata to comment results
-if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then
-  sudo apt-get install -y jq
-  export ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref)
-fi
-
 sudo pip install tabulate
 
 # Python dependencies for tools/run_tests/python_utils/check_on_pr.py
index e9ec07c..b8f3756 100644 (file)
@@ -25,10 +25,7 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db3
 
 # If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
 if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then
-  brew update
-  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"
+  export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"
 fi
 
 set +ex  # rvm script is very verbose and exits with errorcode
index bee5915..c27710f 100644 (file)
@@ -18,10 +18,7 @@ set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH%
 
 @rem If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
 if defined KOKORO_GITHUB_PULL_REQUEST_NUMBER if defined RUN_TESTS_FLAGS (
-  chocolatey install -y jq
-  for /f "usebackq delims=" %%x in (`curl -s https://api.github.com/repos/grpc/grpc/pulls/%KOKORO_GITHUB_PULL_REQUEST_NUMBER% ^| jq -r .base.ref`) do ( 
-    set RUN_TESTS_FLAGS=%RUN_TESTS_FLAGS% --filter_pr_tests --base_branch origin/%%x
-  )
+  set RUN_TESTS_FLAGS=%RUN_TESTS_FLAGS% --filter_pr_tests --base_branch origin/%KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH%
 )
 
 @rem Update DNS settings to:
index 93399f8..5a358ac 100755 (executable)
 
 set -ex
 
-# Download bazel
-temp_dir="$(mktemp -d)"
-wget -q https://github.com/bazelbuild/bazel/releases/download/0.23.2/bazel-0.23.2-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
-
 # change to grpc repo root
 cd $(dirname $0)/../../..
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
+# make sure bazel is available
+tools/bazel version
+
 # 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"
 
-bazel \
+tools/bazel \
   --bazelrc=tools/remote_build/kokoro.bazelrc \
   test \
   --invocation_id="${BAZEL_INVOCATION_ID}" \
index 9c3712a..85b8244 100644 (file)
 
 set -ex
 
-# TODO(jtattermusch): use the latest version of bazel
+# Use bazelisk to download the right bazel version
+wget https://github.com/bazelbuild/bazelisk/releases/download/v0.0.7/bazelisk-linux-amd64
+chmod u+x bazelisk-linux-amd64
 
-# Use --all_incompatible_changes to give an early warning about future
-# bazel incompatibilities.
-EXTRA_FLAGS="--config=opt --cache_test_results=no --all_incompatible_changes"
+# We want bazelisk to run the latest stable version
+export USE_BAZEL_VERSION=latest
+# Use bazelisk instead of our usual //tools/bazel wrapper
+mv bazelisk-linux-amd64 github/grpc/tools/bazel
+
+EXTRA_FLAGS="--config=opt --cache_test_results=no"
 github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
index 7fc8f14..d574638 100755 (executable)
@@ -28,4 +28,4 @@ cd /var/local/git/grpc/test/cpp/end2end
 # iptables is used to drop traffic between client and server
 apt-get install -y iptables
 
-bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all :flaky_network_test --test_env=GRPC_VERBOSITY=debug --test_env=GRPC_TRACE=channel,client_channel,call_error,connectivity_state,tcp
+bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all --test_timeout=1200 :flaky_network_test --test_env=GRPC_TRACE=http --test_env=GRPC_VERBOSITY=DEBUG
index de4db81..377dff7 100644 (file)
@@ -28,3 +28,12 @@ env_vars {
   key: "RUN_TESTS_FLAGS"
   value: "-l all --cloud_to_prod --cloud_to_prod_auth --prod_servers default gateway_v4 --use_docker --internal_ci -t -j 8 --bq_result_table interop_results"
 }
+
+before_action {
+  fetch_keystore {
+    keystore_resource {
+      keystore_config_id: 73836
+      keyname: "interop_to_prod_tests_service_account_key"
+    }
+  }
+}
index 9834aaa..c03383d 100755 (executable)
@@ -26,9 +26,9 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
 
 tools/run_tests/start_port_server.py
 tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/bloat/bloat_diff.py \
-  -d origin/$ghprbTargetBranch || FAILED="true"
+  -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" || FAILED="true"
 tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \
-  -d origin/$ghprbTargetBranch \
+  -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \
   -b $BENCHMARKS_TO_RUN || FAILED="true"
 
 # kill port_server.py to prevent the build from hanging
index f9acd81..a0ce71a 100755 (executable)
@@ -22,10 +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"
+  export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"
 fi
 
 tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true"
index 4ed1b73..49c3d4b 100755 (executable)
@@ -26,7 +26,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
 
 tools/run_tests/start_port_server.py
 tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \
-  -d origin/$ghprbTargetBranch \
+  -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \
   -b bm_fullstack_trickle \
   -l 4 \
   -t $BENCHMARKS_TO_RUN \
@@ -1,4 +1,4 @@
-# Copyright 2017 gRPC authors.
+# Copyright 2019 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.
 # 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_interop.sh"
-gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
-timeout_mins: 240
+build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
+timeout_mins: 60
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
     regex: "github/grpc/reports/**"
   }
 }
+
+env_vars {
+  key: "RUN_TESTS_FLAGS"
+  value: "-f basictests linux corelang --inner_jobs 16 -j 1 --internal_ci --build_only"
+}
index 7321eff..636f979 100644 (file)
@@ -28,3 +28,12 @@ env_vars {
   key: "RUN_TESTS_FLAGS"
   value: "-l all --cloud_to_prod --cloud_to_prod_auth --prod_servers default gateway_v4 --use_docker --internal_ci -t -j 12"
 }
+
+before_action {
+  fetch_keystore {
+    keystore_resource {
+      keystore_config_id: 73836
+      keyname: "interop_to_prod_tests_service_account_key"
+    }
+  }
+}
index 736d759..2414dcc 100755 (executable)
@@ -20,13 +20,11 @@ set -ex
 # Enter the gRPC repo root
 cd $(dirname $0)/../../..
 
-# TODO(jtattermusch): the "ghprbTargetBranch" is Jenkins specific and probably
-# does not work on kokoro?
 AFFECTS_C_CPP=`python -c 'import os; \
                import sys; \
                sys.path.insert(0, "tools/run_tests/python_utils"); \
                import filter_pull_request_tests as filter; \
-               github_target_branch = os.environ.get("ghprbTargetBranch"); \
+               github_target_branch = os.environ.get("KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"); \
                print(filter.affects_c_cpp("origin/%s" % github_target_branch))'`
 
 if [ $AFFECTS_C_CPP == "False" ] ; then
index 2cfc8a2..3c11c74 100644 (file)
@@ -17,7 +17,6 @@
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/macos/grpc_interop_toprod.sh"
 gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
-gfile_resources: "/bigstore/grpc-testing-secrets/interop/service_account/GrpcTesting-726eb1347f15.json"
 timeout_mins: 240
 action {
   define_artifacts {
@@ -25,3 +24,12 @@ action {
     regex: "github/grpc/reports/**"
   }
 }
+
+before_action {
+  fetch_keystore {
+    keystore_resource {
+      keystore_config_id: 73836
+      keyname: "interop_to_prod_tests_service_account_key"
+    }
+  }
+}
index 654da37..13bf58a 100755 (executable)
@@ -33,7 +33,8 @@ tools/run_tests/run_interop_tests.py -l c++ \
     --cloud_to_prod --cloud_to_prod_auth \
     --google_default_creds_use_key_file \
     --prod_servers default gateway_v4 \
-    --service_account_key_file="${KOKORO_GFILE_DIR}/GrpcTesting-726eb1347f15.json" \
+    --service_account_key_file="${KOKORO_KEYSTORE_DIR}/73836_interop_to_prod_tests_service_account_key" \
+    --default_service_account="interop-to-prod-tests@grpc-testing.iam.gserviceaccount.com" \
     --skip_compute_engine_creds --internal_ci -t -j 4 || FAILED="true"
 
 tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
index ea39b0d..17937a3 100755 (executable)
@@ -24,4 +24,4 @@ cd $(dirname $0)/../../..
 source tools/internal_ci/helper_scripts/prepare_build_macos_rc
 
 tools/profiling/ios_bin/binary_size.py \
-  -d origin/$ghprbTargetBranch
+  -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"
index 8f2c534..8abab68 100644 (file)
@@ -13,7 +13,8 @@
 @rem limitations under the License.
 
 @rem TODO(jtattermusch): make this generate less output
-choco install bazel -y --version 0.23.2 --limit-output
+@rem TODO(jtattermusch): use tools/bazel script to keep the versions in sync
+choco install bazel -y --version 0.24.1 --limit-output
 
 cd github/grpc
 set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH%
index 9d5c777..2b37ee7 100644 (file)
@@ -12,11 +12,11 @@ We have continuous nightly test setup to test gRPC backward compatibility betwee
   - `tools/interop_matrix/create_matrix_images.py --git_checkout --release=v1.9.9 --upload_images --language cxx csharp python ruby php`
 - Verify that the new docker image was built successfully and uploaded to GCR.  For example,
   - `gcloud container images list --repository gcr.io/grpc-testing` lists available images.
-  - `gcloud container images list-tags gcr.io/grpc-testing/grpc_interop_java_oracle8` should show an image entry with tag `v1.9.9`.
+  - `gcloud container images list-tags gcr.io/grpc-testing/grpc_interop_java` should show an image entry with tag `v1.9.9`.
   - images can also be viewed in https://pantheon.corp.google.com/gcr/images/grpc-testing?project=grpc-testing
 - Verify the just-created docker client image would pass backward compatibility test (it should).  For example,
-  - `gcloud docker -- pull gcr.io/grpc-testing/grpc_interop_java_oracle8:v1.9.9` followed by
-  - `docker_image=gcr.io/grpc-testing/grpc_interop_java_oracle8:v1.9.9 tools/interop_matrix/testcases/java__master`
+  - `gcloud docker -- pull gcr.io/grpc-testing/grpc_interop_java:v1.9.9` followed by
+  - `docker_image=gcr.io/grpc-testing/grpc_interop_java:v1.9.9 tools/interop_matrix/testcases/java__master`
 - git commit the change and merge it to upstream/master.
 - (Optional) clean up the tmp directory to where grpc source is cloned at `/export/hda3/tmp/grpc_matrix/`.
 For more details on each step, refer to sections below.
index 234c712..05c495f 100644 (file)
@@ -37,12 +37,8 @@ def get_runtimes_for_lang_release(lang, release):
     """Get list of valid runtimes for given release of lang."""
     runtimes = list(LANG_RUNTIME_MATRIX[lang])
     release_info = LANG_RELEASE_MATRIX[lang].get(release)
-    if release_info and release_info.runtime_subset:
-        runtimes = list(release_info.runtime_subset)
-
-    # check that all selected runtimes are valid for given language
-    for runtime in runtimes:
-        assert runtime in LANG_RUNTIME_MATRIX[lang]
+    if release_info and release_info.runtimes:
+        runtimes = list(release_info.runtimes)
     return runtimes
 
 
@@ -55,11 +51,11 @@ def should_build_docker_interop_image_from_release_tag(lang):
     return True
 
 
-# Dictionary of runtimes per language
+# Dictionary of default runtimes per language
 LANG_RUNTIME_MATRIX = {
     'cxx': ['cxx'],  # This is actually debian8.
     'go': ['go1.8', 'go1.11'],
-    'java': ['java_oracle8'],
+    'java': ['java'],
     'python': ['python'],
     'node': ['node'],
     'ruby': ['ruby'],
@@ -71,9 +67,9 @@ LANG_RUNTIME_MATRIX = {
 class ReleaseInfo:
     """Info about a single release of a language"""
 
-    def __init__(self, patch=[], runtime_subset=[], testcases_file=None):
+    def __init__(self, patch=[], runtimes=[], testcases_file=None):
         self.patch = patch
-        self.runtime_subset = runtime_subset
+        self.runtimes = runtimes
         self.testcases_file = testcases_file
 
 
@@ -81,73 +77,116 @@ class ReleaseInfo:
 LANG_RELEASE_MATRIX = {
     'cxx':
     OrderedDict([
-        ('v1.0.1', ReleaseInfo()),
-        ('v1.1.4', ReleaseInfo()),
-        ('v1.2.5', ReleaseInfo()),
-        ('v1.3.9', ReleaseInfo()),
-        ('v1.4.2', ReleaseInfo()),
-        ('v1.6.6', ReleaseInfo()),
-        ('v1.7.2', ReleaseInfo()),
-        ('v1.8.0', ReleaseInfo()),
-        ('v1.9.1', ReleaseInfo()),
-        ('v1.10.1', ReleaseInfo()),
-        ('v1.11.1', ReleaseInfo()),
-        ('v1.12.0', ReleaseInfo()),
-        ('v1.13.0', ReleaseInfo()),
-        ('v1.14.1', ReleaseInfo()),
-        ('v1.15.0', ReleaseInfo()),
-        ('v1.16.0', ReleaseInfo()),
-        ('v1.17.1', ReleaseInfo()),
-        ('v1.18.0', ReleaseInfo()),
-        ('v1.19.0', ReleaseInfo()),
+        ('v1.0.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.1.4', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.2.5', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.3.9', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.4.2', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.6.6', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.7.2', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.8.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.9.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.10.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.11.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.12.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.13.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.14.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.15.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.16.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.17.1', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.18.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
+        ('v1.19.0', ReleaseInfo(testcases_file='cxx__v1.0.1')),
         ('v1.20.0', ReleaseInfo()),
+        ('v1.21.4', ReleaseInfo()),
     ]),
     'go':
-    OrderedDict([
-        ('v1.0.5', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.2.1', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.3.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.4.2', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.5.2', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.6.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.7.4', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.8.2', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.9.2', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.10.1', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.11.3', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.12.2', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.13.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.14.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.15.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.16.0', ReleaseInfo(runtime_subset=['go1.8'])),
-        ('v1.17.0', ReleaseInfo(runtime_subset=['go1.11'])),
-        ('v1.18.0', ReleaseInfo(runtime_subset=['go1.11'])),
-        ('v1.19.0', ReleaseInfo(runtime_subset=['go1.11'])),
-        ('v1.20.0', ReleaseInfo(runtime_subset=['go1.11'])),
-    ]),
+    OrderedDict(
+        [
+            ('v1.0.5',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.2.1',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.3.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.4.2',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.5.2',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.6.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.7.4',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.8.2',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.9.2',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.10.1',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.11.3',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.12.2',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.13.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.14.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.15.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.16.0',
+             ReleaseInfo(runtimes=['go1.8'], testcases_file='go__v1.0.5')),
+            ('v1.17.0',
+             ReleaseInfo(runtimes=['go1.11'], testcases_file='go__v1.0.5')),
+            ('v1.18.0',
+             ReleaseInfo(runtimes=['go1.11'], testcases_file='go__v1.0.5')),
+            ('v1.19.0',
+             ReleaseInfo(runtimes=['go1.11'], testcases_file='go__v1.0.5')),
+            ('v1.20.0', ReleaseInfo(runtimes=['go1.11'])),
+            ('v1.21.0', ReleaseInfo(runtimes=['go1.11'])),
+        ]),
     'java':
     OrderedDict([
-        ('v1.0.3', ReleaseInfo()),
-        ('v1.1.2', ReleaseInfo()),
-        ('v1.2.0', ReleaseInfo()),
-        ('v1.3.1', ReleaseInfo()),
-        ('v1.4.0', ReleaseInfo()),
-        ('v1.5.0', ReleaseInfo()),
-        ('v1.6.1', ReleaseInfo()),
-        ('v1.7.0', ReleaseInfo()),
-        ('v1.8.0', ReleaseInfo()),
-        ('v1.9.1', ReleaseInfo()),
-        ('v1.10.1', ReleaseInfo()),
-        ('v1.11.0', ReleaseInfo()),
-        ('v1.12.0', ReleaseInfo()),
-        ('v1.13.1', ReleaseInfo()),
-        ('v1.14.0', ReleaseInfo()),
-        ('v1.15.0', ReleaseInfo()),
-        ('v1.16.1', ReleaseInfo()),
-        ('v1.17.1', ReleaseInfo()),
-        ('v1.18.0', ReleaseInfo()),
-        ('v1.19.0', ReleaseInfo()),
-        ('v1.20.0', ReleaseInfo()),
+        ('v1.0.3',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.1.2',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.2.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.3.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.4.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.5.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.6.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.7.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.8.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.9.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.10.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.11.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.12.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.13.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.14.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.15.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.16.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.17.1',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.18.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.19.0',
+         ReleaseInfo(runtimes=['java_oracle8'], testcases_file='java__v1.0.3')),
+        ('v1.20.0', ReleaseInfo(runtimes=['java_oracle8'])),
+        ('v1.21.0', ReleaseInfo(runtimes=['java_oracle8'])),
     ]),
     'python':
     OrderedDict([
@@ -171,6 +210,7 @@ LANG_RELEASE_MATRIX = {
         ('v1.18.0', ReleaseInfo()),
         ('v1.19.0', ReleaseInfo()),
         ('v1.20.0', ReleaseInfo()),
+        ('v1.21.4', ReleaseInfo()),
     ]),
     'node':
     OrderedDict([
@@ -197,50 +237,54 @@ LANG_RELEASE_MATRIX = {
                  'tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh',
              ],
              testcases_file='ruby__v1.0.1')),
-        ('v1.1.4', ReleaseInfo()),
-        ('v1.2.5', ReleaseInfo()),
-        ('v1.3.9', ReleaseInfo()),
-        ('v1.4.2', ReleaseInfo()),
-        ('v1.6.6', ReleaseInfo()),
-        ('v1.7.2', ReleaseInfo()),
-        ('v1.8.0', ReleaseInfo()),
-        ('v1.9.1', ReleaseInfo()),
-        ('v1.10.1', ReleaseInfo()),
-        ('v1.11.1', ReleaseInfo()),
-        ('v1.12.0', ReleaseInfo()),
-        ('v1.13.0', ReleaseInfo()),
-        ('v1.14.1', ReleaseInfo()),
-        ('v1.15.0', ReleaseInfo()),
-        ('v1.16.0', ReleaseInfo()),
-        ('v1.17.1', ReleaseInfo()),
+        ('v1.1.4', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.2.5', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.3.9', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.4.2', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.6.6', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.7.2', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.8.0', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.9.1', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.10.1', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.11.1', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.12.0', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.13.0', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.14.1', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.15.0', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.16.0', ReleaseInfo(testcases_file='ruby__v1.1.4')),
+        ('v1.17.1', ReleaseInfo(testcases_file='ruby__v1.1.4')),
         ('v1.18.0',
          ReleaseInfo(patch=[
              'tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh',
          ])),
+        ('v1.19.0', ReleaseInfo()),
+        ('v1.20.0', ReleaseInfo()),
+        ('v1.21.4', ReleaseInfo()),
         # TODO: https://github.com/grpc/grpc/issues/18262.
         # If you are not encountering the error in above issue
         # go ahead and upload the docker image for new releases.
     ]),
     'php':
     OrderedDict([
-        ('v1.0.1', ReleaseInfo()),
-        ('v1.1.4', ReleaseInfo()),
-        ('v1.2.5', ReleaseInfo()),
-        ('v1.3.9', ReleaseInfo()),
-        ('v1.4.2', ReleaseInfo()),
-        ('v1.6.6', ReleaseInfo()),
-        ('v1.7.2', ReleaseInfo()),
-        ('v1.8.0', ReleaseInfo()),
-        ('v1.9.1', ReleaseInfo()),
-        ('v1.10.1', ReleaseInfo()),
-        ('v1.11.1', ReleaseInfo()),
-        ('v1.12.0', ReleaseInfo()),
-        ('v1.13.0', ReleaseInfo()),
-        ('v1.14.1', ReleaseInfo()),
-        ('v1.15.0', ReleaseInfo()),
-        ('v1.16.0', ReleaseInfo()),
-        ('v1.17.1', ReleaseInfo()),
+        ('v1.0.1', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.1.4', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.2.5', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.3.9', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.4.2', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.6.6', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.7.2', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.8.0', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.9.1', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.10.1', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.11.1', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.12.0', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.13.0', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.14.1', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.15.0', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.16.0', ReleaseInfo(testcases_file='php__v1.0.1')),
+        ('v1.17.1', ReleaseInfo(testcases_file='php__v1.0.1')),
         ('v1.18.0', ReleaseInfo()),
+        ('v1.21.4', ReleaseInfo()),
         # TODO:https://github.com/grpc/grpc/issues/18264
         # Error in above issues needs to be resolved.
     ]),
@@ -272,5 +316,6 @@ LANG_RELEASE_MATRIX = {
         ('v1.18.0', ReleaseInfo(testcases_file='csharp__v1.18.0')),
         ('v1.19.0', ReleaseInfo(testcases_file='csharp__v1.18.0')),
         ('v1.20.0', ReleaseInfo()),
+        ('v1.21.4', ReleaseInfo()),
     ]),
 }
index fa33fa4..b3e3ee6 100755 (executable)
@@ -60,7 +60,7 @@ fi
 echo $client_lang
 
 ${GRPC_ROOT}/tools/run_tests/run_interop_tests.py -l $client_lang --use_docker \
-  --cloud_to_prod --prod_servers default gateway_v4 --manual_run
+  --cloud_to_prod --prod_servers default gateway_v4 --manual_run --custom_credentials_type tls
 
 trap cleanup EXIT
 # TODO(adelez): add test auth tests but do not run if not testing on GCE.
index 3f92c8e..120ba08 100755 (executable)
@@ -86,6 +86,8 @@ argp.add_argument(
     type=str,
     nargs='?',
     help='Upload test results to a specified BQ table.')
+# Requests will be routed through specified VIP by default.
+# See go/grpc-interop-tests (internal-only) for details.
 argp.add_argument(
     '--server_host',
     default='74.125.206.210',
index 629da1a..5739d66 100755 (executable)
@@ -1,20 +1,22 @@
 #!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_cxx:78de6f80-524d-4bc9-bfb2-f00c24ceafed}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+# DO NOT MODIFY
+# This file is generated by run_interop_tests.py/create_testcases.sh
+echo "Testing ${docker_image:=grpc_interop_cxx:f5a2f91d-342a-4bc8-a5ca-eb113dd3a8a2}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
diff --git a/tools/interop_matrix/testcases/cxx__v1.0.1 b/tools/interop_matrix/testcases/cxx__v1.0.1
new file mode 100755 (executable)
index 0000000..629da1a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_cxx:78de6f80-524d-4bc9-bfb2-f00c24ceafed}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
index a7f83ae..ab83d6b 100755 (executable)
@@ -1,20 +1,22 @@
 #!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_go:dd8fbf3a-4964-4387-9997-5dadeea09835}"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+# DO NOT MODIFY
+# This file is generated by run_interop_tests.py/create_testcases.sh
+echo "Testing ${docker_image:=grpc_interop_go:45617187-1a75-4f2f-b7af-c602d882bbc0}"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
diff --git a/tools/interop_matrix/testcases/go__v1.0.5 b/tools/interop_matrix/testcases/go__v1.0.5
new file mode 100755 (executable)
index 0000000..a7f83ae
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_go:dd8fbf3a-4964-4387-9997-5dadeea09835}"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
index 95a9c28..4f576db 100755 (executable)
@@ -1,20 +1,22 @@
 #!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_java:a764b50c-1788-4387-9b9e-5cfa93927006}"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+# DO NOT MODIFY
+# This file is generated by run_interop_tests.py/create_testcases.sh
+echo "Testing ${docker_image:=grpc_interop_java:564ef0d0-f4d8-4611-88a9-bb6a99bf68a8}"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
diff --git a/tools/interop_matrix/testcases/java__v1.0.3 b/tools/interop_matrix/testcases/java__v1.0.3
new file mode 100755 (executable)
index 0000000..95a9c28
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_java:a764b50c-1788-4387-9b9e-5cfa93927006}"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
index f99cb17..3d7e997 100755 (executable)
@@ -1,20 +1,22 @@
 #!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_php:b290f404-9940-4968-8fc2-19f5291c8eb7}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+# DO NOT MODIFY
+# This file is generated by run_interop_tests.py/create_testcases.sh
+echo "Testing ${docker_image:=grpc_interop_php:e00a3b45-27f0-4143-8c23-128cb4ffc46a}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
diff --git a/tools/interop_matrix/testcases/php__v1.0.1 b/tools/interop_matrix/testcases/php__v1.0.1
new file mode 100755 (executable)
index 0000000..f99cb17
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_php:b290f404-9940-4968-8fc2-19f5291c8eb7}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
index 39e1601..0fc2381 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 # DO NOT MODIFY
 # This file is generated by run_interop_tests.py/create_testcases.sh
-echo "Testing ${docker_image:=grpc_interop_python:4fa5bb4b-5d57-4882-8c8e-551fb899b86a}"
+echo "Testing ${docker_image:=grpc_interop_python:8f586cb2-054e-4653-91a4-3ffdc94e71fc}"
 docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py37_native/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true\""
 docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py37_native/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true\""
 docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py37_native/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true\""
index 784ba68..670171f 100755 (executable)
@@ -1,20 +1,22 @@
 #!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_ruby:6bd1f0eb-51a4-4ad8-861c-1cbd7a929f33}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+# DO NOT MODIFY
+# This file is generated by run_interop_tests.py/create_testcases.sh
+echo "Testing ${docker_image:=grpc_interop_ruby:e60da8f6-d7e0-47d3-8bfe-330ce76077b4}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true"
diff --git a/tools/interop_matrix/testcases/ruby__v1.1.4 b/tools/interop_matrix/testcases/ruby__v1.1.4
new file mode 100755 (executable)
index 0000000..784ba68
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_ruby:6bd1f0eb-51a4-4ad8-861c-1cbd7a929f33}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
index 69394fe..63b49c5 100644 (file)
@@ -84,4 +84,4 @@ build:ubsan --copt=-gmlt
 # TODO(jtattermusch): use more reasonable test timeout
 build:ubsan --test_timeout=3600
 # override the config-agnostic crosstool_top
-build:ubsan --crosstool_top=@bazel_toolchains//configs/experimental/ubuntu16_04_clang/1.2/bazel_0.21.0/ubsan:toolchain
+build:ubsan --crosstool_top=@bazel_toolchains//configs/experimental/ubuntu16_04_clang/1.2/bazel_0.23.0/ubsan:toolchain
index fd68a4d..35a561e 100644 (file)
@@ -336,7 +336,6 @@ def targets():
         PythonDistribTest('linux', 'x64', 'ubuntu1404', source=True),
         PythonDistribTest('linux', 'x64', 'ubuntu1604', source=True),
         RubyDistribTest('linux', 'x64', 'wheezy'),
-        RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_2'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_3'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_4'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_5'),
index 39ee76b..3143f2c 100644 (file)
   {
     "deps": [
       "benchmark", 
+      "bm_callback_test_service_impl", 
+      "gpr", 
+      "grpc++_test_config", 
+      "grpc++_test_util_unsecure", 
+      "grpc++_unsecure", 
+      "grpc_benchmark", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/cpp/microbenchmarks/callback_streaming_ping_pong.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "bm_callback_streaming_ping_pong", 
+    "src": [
+      "test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc", 
+      "test/cpp/microbenchmarks/callback_streaming_ping_pong.h"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "benchmark", 
+      "bm_callback_test_service_impl", 
+      "gpr", 
+      "grpc++_test_config", 
+      "grpc++_test_util_unsecure", 
+      "grpc++_unsecure", 
+      "grpc_benchmark", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/cpp/microbenchmarks/callback_unary_ping_pong.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "bm_callback_unary_ping_pong", 
+    "src": [
+      "test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc", 
+      "test/cpp/microbenchmarks/callback_unary_ping_pong.h"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "benchmark", 
       "gpr", 
       "grpc++_test_config", 
       "grpc++_test_util_unsecure", 
       "gpr", 
       "grpc", 
       "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "test_tcp_server"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "port_sharing_end2end_test", 
+    "src": [
+      "test/cpp/end2end/port_sharing_end2end_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++", 
       "grpc++_proto_reflection_desc_db", 
       "grpc++_reflection", 
       "grpc++_test_util", 
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "badreq_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/badreq.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "connection_prefix_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/connection_prefix.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "duplicate_header_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/duplicate_header.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "head_of_line_blocking_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/head_of_line_blocking.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "headers_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/headers.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "initial_settings_frame_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/initial_settings_frame.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "large_metadata_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/large_metadata.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "server_registered_method_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/server_registered_method.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "simple_request_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/simple_request.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "unknown_frame_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/unknown_frame.cc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "window_overflow_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/window_overflow.cc"
     "type": "lib"
   }, 
   {
+    "deps": [
+      "benchmark", 
+      "gpr", 
+      "grpc++_test_config", 
+      "grpc++_test_util_unsecure", 
+      "grpc++_unsecure", 
+      "grpc_benchmark", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/echo.grpc.pb.h", 
+      "src/proto/grpc/testing/echo.pb.h", 
+      "src/proto/grpc/testing/echo_mock.grpc.pb.h", 
+      "test/cpp/microbenchmarks/callback_test_service.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "bm_callback_test_service_impl", 
+    "src": [
+      "test/cpp/microbenchmarks/callback_test_service.cc", 
+      "test/cpp/microbenchmarks/callback_test_service.h"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
     "deps": [], 
     "headers": [
       "test/cpp/naming/dns_test_util.h"
       "test/core/bad_client/bad_client.h"
     ], 
     "is_filegroup": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "bad_client_test", 
     "src": [
       "test/core/bad_client/bad_client.cc", 
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
+      "src/core/lib/slice/slice_utils.h", 
       "src/core/lib/slice/slice_weak_hash_table.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
+      "src/core/lib/slice/slice_utils.h", 
       "src/core/lib/slice/slice_weak_hash_table.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
       "src/core/ext/filters/client_channel/server_address.h", 
       "src/core/ext/filters/client_channel/service_config.h", 
       "src/core/ext/filters/client_channel/subchannel.h", 
+      "src/core/ext/filters/client_channel/subchannel_interface.h", 
       "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
     ], 
     "is_filegroup": true, 
       "src/core/ext/filters/client_channel/service_config.h", 
       "src/core/ext/filters/client_channel/subchannel.cc", 
       "src/core/ext/filters/client_channel/subchannel.h", 
+      "src/core/ext/filters/client_channel/subchannel_interface.h", 
       "src/core/ext/filters/client_channel/subchannel_pool_interface.cc", 
       "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
     ], 
       "include/grpcpp/impl/codegen/channel_interface.h", 
       "include/grpcpp/impl/codegen/client_callback.h", 
       "include/grpcpp/impl/codegen/client_context.h", 
+      "include/grpcpp/impl/codegen/client_context_impl.h", 
       "include/grpcpp/impl/codegen/client_interceptor.h", 
       "include/grpcpp/impl/codegen/client_unary_call.h", 
       "include/grpcpp/impl/codegen/completion_queue.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_context_impl.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/channel_interface.h", 
       "include/grpcpp/impl/codegen/client_callback.h", 
       "include/grpcpp/impl/codegen/client_context.h", 
+      "include/grpcpp/impl/codegen/client_context_impl.h", 
       "include/grpcpp/impl/codegen/client_interceptor.h", 
       "include/grpcpp/impl/codegen/client_unary_call.h", 
       "include/grpcpp/impl/codegen/completion_queue.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_context_impl.h", 
       "include/grpcpp/impl/codegen/server_interceptor.h", 
       "include/grpcpp/impl/codegen/server_interface.h", 
       "include/grpcpp/impl/codegen/service_type.h", 
       "include/grpcpp/support/stub_options.h", 
       "include/grpcpp/support/sync_stream.h", 
       "include/grpcpp/support/time.h", 
+      "include/grpcpp/support/validate_service_config.h", 
       "src/cpp/client/create_channel_internal.h", 
       "src/cpp/common/channel_filter.h", 
       "src/cpp/server/dynamic_thread_pool.h", 
+      "src/cpp/server/external_connection_acceptor_impl.h", 
       "src/cpp/server/health/default_health_check_service.h", 
       "src/cpp/server/thread_pool_interface.h", 
       "src/cpp/thread_manager/thread_manager.h"
       "include/grpcpp/support/stub_options.h", 
       "include/grpcpp/support/sync_stream.h", 
       "include/grpcpp/support/time.h", 
+      "include/grpcpp/support/validate_service_config.h", 
       "src/cpp/client/channel_cc.cc", 
       "src/cpp/client/client_context.cc", 
       "src/cpp/client/client_interceptor.cc", 
       "src/cpp/common/core_codegen.cc", 
       "src/cpp/common/resource_quota_cc.cc", 
       "src/cpp/common/rpc_method.cc", 
+      "src/cpp/common/validate_service_config.cc", 
       "src/cpp/common/version_cc.cc", 
       "src/cpp/server/async_generic_service.cc", 
       "src/cpp/server/channel_argument_option.cc", 
       "src/cpp/server/create_default_thread_pool.cc", 
       "src/cpp/server/dynamic_thread_pool.cc", 
       "src/cpp/server/dynamic_thread_pool.h", 
+      "src/cpp/server/external_connection_acceptor_impl.cc", 
+      "src/cpp/server/external_connection_acceptor_impl.h", 
       "src/cpp/server/health/default_health_check_service.cc", 
       "src/cpp/server/health/default_health_check_service.h", 
       "src/cpp/server/health/health_check_service.cc", 
index c156c83..37a69a4 100644 (file)
     "flaky": false, 
     "gtest": false, 
     "language": "c++", 
+    "name": "bm_callback_streaming_ping_pong", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": true, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "bm_callback_unary_ping_pong", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": true, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
     "name": "bm_channel", 
     "platforms": [
       "linux", 
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "port_sharing_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": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "proto_server_reflection_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "badreq_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "connection_prefix_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "duplicate_header_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "head_of_line_blocking_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "headers_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "initial_settings_frame_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "large_metadata_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "server_registered_method_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "simple_request_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "unknown_frame_bad_client_test", 
     "platforms": [
       "linux", 
     ], 
     "flaky": false, 
     "gtest": false, 
-    "language": "c", 
+    "language": "c++", 
     "name": "window_overflow_bad_client_test", 
     "platforms": [
       "linux", 
index 567c628..e71d308 100755 (executable)
@@ -145,7 +145,6 @@ class CSharpLanguage:
     def unimplemented_test_cases(self):
         return _SKIP_SERVER_COMPRESSION + \
             _SKIP_DATA_FRAME_PADDING + \
-            _SKIP_SPECIAL_STATUS_MESSAGE + \
             _SKIP_GOOGLE_DEFAULT_CREDS + \
             _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS
 
@@ -178,7 +177,6 @@ class CSharpCoreCLRLanguage:
     def unimplemented_test_cases(self):
         return _SKIP_SERVER_COMPRESSION + \
             _SKIP_DATA_FRAME_PADDING + \
-            _SKIP_SPECIAL_STATUS_MESSAGE + \
             _SKIP_GOOGLE_DEFAULT_CREDS + \
             _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS
 
@@ -192,7 +190,7 @@ class CSharpCoreCLRLanguage:
 class AspNetCoreLanguage:
 
     def __init__(self):
-        self.client_cwd = '../grpc-dotnet'
+        self.client_cwd = '../grpc-dotnet/testassets/InteropTestsClient/bin/Debug/netcoreapp3.0'
         self.server_cwd = '../grpc-dotnet/testassets/InteropTestsWebsite/bin/Debug/netcoreapp3.0'
         self.safename = str(self)
 
@@ -200,8 +198,7 @@ class AspNetCoreLanguage:
         return {}
 
     def client_cmd(self, args):
-        # attempt to run client should fail
-        return ['dotnet' 'exec', 'CLIENT_NOT_SUPPORTED'] + args
+        return ['dotnet', 'exec', 'InteropTestsClient.dll'] + args
 
     def server_cmd(self, args):
         return ['dotnet', 'exec', 'InteropTestsWebsite.dll'] + args
@@ -210,11 +207,11 @@ class AspNetCoreLanguage:
         return {}
 
     def unimplemented_test_cases(self):
-        # aspnetcore doesn't have a client so ignore all test cases.
-        return _TEST_CASES + _AUTH_TEST_CASES
+        return _SKIP_COMPRESSION + \
+            _AUTH_TEST_CASES
 
     def unimplemented_test_cases_server(self):
-        return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE
+        return _SKIP_COMPRESSION
 
     def __str__(self):
         return 'aspnetcore'
@@ -737,6 +734,10 @@ _SERVERS_FOR_ALTS_TEST_CASES = ['java', 'go', 'c++']
 
 _TRANSPORT_SECURITY_OPTIONS = ['tls', 'alts', 'insecure']
 
+_CUSTOM_CREDENTIALS_TYPE_OPTIONS = [
+    'tls', 'google_default_credentials', 'compute_engine_channel_creds'
+]
+
 DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
 
 
@@ -806,22 +807,17 @@ def compute_engine_creds_required(language, test_case):
     return False
 
 
-def auth_options(language,
-                 test_case,
-                 google_default_creds_use_key_file,
-                 service_account_key_file=None):
+def auth_options(language, test_case, google_default_creds_use_key_file,
+                 service_account_key_file, default_service_account):
     """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
 
     language = str(language)
     cmdargs = []
     env = {}
 
-    if not service_account_key_file:
-        # this file path only works inside docker
-        service_account_key_file = '/root/service_account/GrpcTesting-726eb1347f15.json'
     oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
     key_file_arg = '--service_account_key_file=%s' % service_account_key_file
-    default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
+    default_account_arg = '--default_service_account=%s' % default_service_account
 
     if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
         if language in [
@@ -872,6 +868,7 @@ def cloud_to_prod_jobspec(language,
                           auth=False,
                           manual_cmd_log=None,
                           service_account_key_file=None,
+                          default_service_account=None,
                           transport_security='tls'):
     """Creates jobspec for cloud-to-prod interop test"""
     container_name = None
@@ -899,9 +896,9 @@ def cloud_to_prod_jobspec(language,
     cmdargs = cmdargs + transport_security_options
     environ = dict(language.cloud_to_prod_env(), **language.global_env())
     if auth:
-        auth_cmdargs, auth_env = auth_options(language, test_case,
-                                              google_default_creds_use_key_file,
-                                              service_account_key_file)
+        auth_cmdargs, auth_env = auth_options(
+            language, test_case, google_default_creds_use_key_file,
+            service_account_key_file, default_service_account)
         cmdargs += auth_cmdargs
         environ.update(auth_env)
     cmdline = bash_cmdline(language.client_cmd(cmdargs))
@@ -1151,7 +1148,8 @@ def aggregate_http2_results(stdout):
     }
 
 
-# A dictionary of prod servers to test.
+# A dictionary of prod servers to test against.
+# See go/grpc-interop-tests (internal-only) for details.
 prod_servers = {
     'default': 'grpc-test.sandbox.googleapis.com',
     'gateway_v4': 'grpc-test4.sandbox.googleapis.com',
@@ -1209,12 +1207,17 @@ argp.add_argument(
     help=
     'Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
     default=[])
+# TODO(jtattermusch): the default service_account_key_file only works when --use_docker is used.
 argp.add_argument(
     '--service_account_key_file',
     type=str,
-    help=
-    'Override the default service account key file to use for auth interop tests.',
-    default=None)
+    help='The service account key file to use for some auth interop tests.',
+    default='/root/service_account/grpc-testing-ebe7c1ac7381.json')
+argp.add_argument(
+    '--default_service_account',
+    type=str,
+    help='Default GCE service account email to use for some auth interop tests.',
+    default='830293263384-compute@developer.gserviceaccount.com')
 argp.add_argument(
     '-t', '--travis', default=False, action='store_const', const=True)
 argp.add_argument(
@@ -1266,6 +1269,14 @@ argp.add_argument(
     const=True,
     help='Which transport security mechanism to use.')
 argp.add_argument(
+    '--custom_credentials_type',
+    choices=_CUSTOM_CREDENTIALS_TYPE_OPTIONS,
+    default=_CUSTOM_CREDENTIALS_TYPE_OPTIONS,
+    nargs='+',
+    help=
+    'Credential types to test in the cloud_to_prod setup. Default is to test with all creds types possible.'
+)
+argp.add_argument(
     '--skip_compute_engine_creds',
     default=False,
     action='store_const',
@@ -1434,39 +1445,20 @@ try:
                 for test_case in _TEST_CASES:
                     if not test_case in language.unimplemented_test_cases():
                         if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE:
-                            tls_test_job = cloud_to_prod_jobspec(
-                                language,
-                                test_case,
-                                server_host_nickname,
-                                prod_servers[server_host_nickname],
-                                google_default_creds_use_key_file=args.
-                                google_default_creds_use_key_file,
-                                docker_image=docker_images.get(str(language)),
-                                manual_cmd_log=client_manual_cmd_log,
-                                service_account_key_file=args.
-                                service_account_key_file,
-                                transport_security='tls')
-                            jobs.append(tls_test_job)
-                            if str(language) in [
-                                    'c++', 'go', 'java', 'javaokhttp'
-                            ]:
-                                google_default_creds_test_job = cloud_to_prod_jobspec(
-                                    language,
-                                    test_case,
-                                    server_host_nickname,
-                                    prod_servers[server_host_nickname],
-                                    google_default_creds_use_key_file=args.
-                                    google_default_creds_use_key_file,
-                                    docker_image=docker_images.get(
-                                        str(language)),
-                                    manual_cmd_log=client_manual_cmd_log,
-                                    service_account_key_file=args.
-                                    service_account_key_file,
-                                    transport_security=
-                                    'google_default_credentials')
-                                jobs.append(google_default_creds_test_job)
-                            if str(language) in ['go', 'java', 'javaokhttp']:
-                                compute_engine_channel_creds_test_job = cloud_to_prod_jobspec(
+                            for transport_security in args.custom_credentials_type:
+                                # google_default_credentials not yet supported by all languages
+                                if transport_security == 'google_default_credentials' and str(
+                                        language) not in [
+                                            'c++', 'go', 'java', 'javaokhttp'
+                                        ]:
+                                    continue
+                                # compute_engine_channel_creds not yet supported by all languages
+                                if transport_security == 'compute_engine_channel_creds' and str(
+                                        language) not in [
+                                            'go', 'java', 'javaokhttp'
+                                        ]:
+                                    continue
+                                test_job = cloud_to_prod_jobspec(
                                     language,
                                     test_case,
                                     server_host_nickname,
@@ -1478,11 +1470,10 @@ try:
                                     manual_cmd_log=client_manual_cmd_log,
                                     service_account_key_file=args.
                                     service_account_key_file,
-                                    transport_security=
-                                    'compute_engine_channel_creds')
-                                jobs.append(
-                                    compute_engine_channel_creds_test_job)
-
+                                    default_service_account=args.
+                                    default_service_account,
+                                    transport_security=transport_security)
+                                jobs.append(test_job)
             if args.http2_interop:
                 for test_case in _HTTP2_TEST_CASES:
                     test_job = cloud_to_prod_jobspec(
@@ -1495,6 +1486,7 @@ try:
                         docker_image=docker_images.get(str(http2Interop)),
                         manual_cmd_log=client_manual_cmd_log,
                         service_account_key_file=args.service_account_key_file,
+                        default_service_account=args.default_service_account,
                         transport_security=args.transport_security)
                     jobs.append(test_job)
 
@@ -1514,6 +1506,8 @@ try:
                                 transport_security = 'compute_engine_channel_creds'
                             else:
                                 transport_security = 'tls'
+                            if transport_security not in args.custom_credentials_type:
+                                continue
                             test_job = cloud_to_prod_jobspec(
                                 language,
                                 test_case,
@@ -1526,6 +1520,8 @@ try:
                                 manual_cmd_log=client_manual_cmd_log,
                                 service_account_key_file=args.
                                 service_account_key_file,
+                                default_service_account=args.
+                                default_service_account,
                                 transport_security=transport_security)
                             jobs.append(test_job)
     for server in args.override_server:
index a7a9dbd..43d8c64 100755 (executable)
@@ -753,7 +753,7 @@ class PythonLanguage(object):
     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'
+                'python2.7', 'python3.5', 'python3.6', 'python3.7', 'python3.8'
         ]:
             return 'stretch_' + self.args.compiler[len('python'):]
         elif self.args.compiler == 'python_alpine':
@@ -829,6 +829,12 @@ class PythonLanguage(object):
             minor='7',
             bits=bits,
             config_vars=config_vars)
+        python38_config = _python_config_generator(
+            name='py38',
+            major='3',
+            minor='8',
+            bits=bits,
+            config_vars=config_vars)
         pypy27_config = _pypy_config_generator(
             name='pypy', major='2', config_vars=config_vars)
         pypy32_config = _pypy_config_generator(
@@ -852,6 +858,8 @@ class PythonLanguage(object):
             return (python36_config,)
         elif args.compiler == 'python3.7':
             return (python37_config,)
+        elif args.compiler == 'python3.8':
+            return (python38_config,)
         elif args.compiler == 'pypy':
             return (pypy27_config,)
         elif args.compiler == 'pypy3':
@@ -865,6 +873,7 @@ class PythonLanguage(object):
                 python35_config,
                 python36_config,
                 python37_config,
+                # TODO: Add Python 3.8 once it's released.
             )
         else:
             raise Exception('Compiler %s not supported.' % args.compiler)
@@ -1340,9 +1349,10 @@ argp.add_argument(
     choices=[
         'default', 'gcc4.4', 'gcc4.6', 'gcc4.8', 'gcc4.9', 'gcc5.3', 'gcc7.2',
         'gcc_musl', 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7', 'clang7.0',
-        'python2.7', 'python3.4', 'python3.5', 'python3.6', 'python3.7', 'pypy',
-        'pypy3', 'python_alpine', 'all_the_cpythons', 'electron1.3',
-        'electron1.6', 'coreclr', 'cmake', 'cmake_vs2015', 'cmake_vs2017'
+        'python2.7', 'python3.4', 'python3.5', 'python3.6', 'python3.7',
+        'python3.8', 'pypy', 'pypy3', 'python_alpine', 'all_the_cpythons',
+        'electron1.3', 'electron1.6', 'coreclr', 'cmake', 'cmake_vs2015',
+        'cmake_vs2017'
     ],
     default='default',
     help=
index 2017f58..65aa721 100755 (executable)
@@ -45,7 +45,7 @@ _TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly'
 _GRPC_DEP_NAMES = [
     'upb',
     'boringssl',
-    'com_github_madler_zlib',
+    'zlib',
     'com_google_protobuf',
     'com_github_google_googletest',
     'com_github_gflags_gflags',
index b15b8d3..487479b 100755 (executable)
@@ -38,7 +38,7 @@ cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
  ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
  6599cac0965be8e5a835ab7a5684bbef033d5ad0 third_party/libcxx (heads/release_60)
  9245d481eb3e890f708ff2d7dadf2a10c04748ba third_party/libcxxabi (heads/release_60)
582743bf40c5d3639a70f98f183914a2c0cd0680 third_party/protobuf (v3.7.0-rc.2-20-g582743bf)
09745575a923640154bcf307fba8aedff47f240a third_party/protobuf (v3.7.0-rc.2-247-g09745575)
  e143189bf6f37b3957fb31743df6a1bcf4a8c685 third_party/protoc-gen-validate (v0.0.10)
  fa88c6017ddb490aa78c57bea682193f533ed69a third_party/upb (heads/master)
  cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
index 0eeceb4..cca9859 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python
 
 # Copyright 2017 gRPC authors.
 #
@@ -27,4 +27,4 @@ import python_utils.start_port_server as start_port_server
 
 start_port_server.start_port_server()
 
-print "Port server started successfully"
+print("Port server started successfully")